From eda9f838366cd46f09e3bb3401cfaf7775e21daf Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 29 Apr 2018 15:32:22 +0300 Subject: [PATCH 001/186] Add activeBeatmapPreview variable for tracking beatmap preview playback --- osu.Game/Overlays/Direct/PlayButton.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 4913b11ae1..dae3b63a8f 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays.Direct { public class PlayButton : Container { + private static PlayButton activeBeatmapPreview; public readonly Bindable Playing = new Bindable(); public Track Preview { get; private set; } @@ -131,6 +132,9 @@ namespace osu.Game.Overlays.Direct if (playing) { + if (activeBeatmapPreview != null) + activeBeatmapPreview.Playing.Value = false; + if (Preview == null) { beginAudioLoad(); @@ -140,6 +144,7 @@ namespace osu.Game.Overlays.Direct Preview.Restart(); audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + activeBeatmapPreview = this; } else { From 56c1c2beca733efdeee32e7d9a0779e0dc4ca524 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Sun, 29 Apr 2018 15:50:02 +0300 Subject: [PATCH 002/186] Remove redundant multiple previews handling from PaginatedBeatmapContainer --- .../Beatmaps/PaginatedBeatmapContainer.cs | 27 ++----------------- .../Profile/Sections/BeatmapsSection.cs | 10 ------- 2 files changed, 2 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 3fec9d8697..0b06acd426 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -1,14 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; -using OpenTK; +using System.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Direct; using osu.Game.Users; -using System.Linq; +using OpenTK; namespace osu.Game.Overlays.Profile.Sections.Beatmaps { @@ -18,10 +17,6 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps private readonly BeatmapSetType type; - private DirectPanel currentlyPlaying; - - public event Action BeganPlayingPreview; - public PaginatedBeatmapContainer(BeatmapSetType type, Bindable user, string header, string missing = "None... yet.") : base(user, header, missing) { @@ -56,28 +51,10 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)); ItemsContainer.Add(panel); - - panel.PreviewPlaying.ValueChanged += isPlaying => - { - StopPlayingPreview(); - - if (isPlaying) - { - BeganPlayingPreview?.Invoke(this); - currentlyPlaying = panel; - } - }; } }; Api.Queue(req); } - - public void StopPlayingPreview() - { - if (currentlyPlaying == null) return; - currentlyPlaying.PreviewPlaying.Value = false; - currentlyPlaying = null; - } } } diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index 92abd20f93..367d096c16 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Profile.Sections.Beatmaps; @@ -22,15 +21,6 @@ namespace osu.Game.Overlays.Profile.Sections new PaginatedBeatmapContainer(BeatmapSetType.Unranked, User, "Pending Beatmaps"), new PaginatedBeatmapContainer(BeatmapSetType.Graveyard, User, "Graveyarded Beatmaps"), }; - - foreach (var paginatedBeatmapContainer in Children.OfType()) - { - paginatedBeatmapContainer.BeganPlayingPreview += _ => - { - foreach (var bc in Children.OfType()) - bc.StopPlayingPreview(); - }; - } } } } From 7cffabf7f931c367eb02ce8a0fc40342d5f6122d Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Tue, 8 May 2018 22:55:48 +0300 Subject: [PATCH 003/186] Introduce PreviewTrackManager --- osu.Game/Audio/PreviewTrackManager.cs | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 osu.Game/Audio/PreviewTrackManager.cs diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs new file mode 100644 index 0000000000..55addac8ad --- /dev/null +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Configuration; +using osu.Framework.IO.Stores; + +namespace osu.Game.Audio +{ + public class PreviewTrackManager : TrackManager + { + private AudioManager audio; + private Track currentTrack; + private readonly BindableDouble muteBindable; + + public PreviewTrackManager() + : base(new OnlineStore()) + { + muteBindable = new BindableDouble(); + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio, FrameworkConfigManager config) + { + this.audio = audio; + + audio.AddItem(this); + + config.BindWith(FrameworkSetting.VolumeMusic, Volume); + } + + protected override void UpdateState() + { + if (currentTrack?.HasCompleted ?? false) + onStop(); + + base.UpdateState(); + } + + public void Play(Track track) + { + currentTrack?.Stop(); + currentTrack = track; + currentTrack.Restart(); + onPlay(); + } + + private void onPlay() => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + + public void Stop() + { + currentTrack?.Stop(); + onStop(); + } + + private void onStop() => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + } +} From ad50f7faf10cdc5c4090d5ff58db5cc906debe72 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 9 May 2018 14:51:04 +0300 Subject: [PATCH 004/186] Make PreviewTrackManager a Component in order to use DI --- osu.Game/Audio/PreviewTrackManager.cs | 60 +++++++++++++++------------ 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 55addac8ad..2e5f26bcf4 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -1,60 +1,66 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; +using osu.Framework.Graphics; using osu.Framework.IO.Stores; +using osu.Game.Beatmaps; namespace osu.Game.Audio { - public class PreviewTrackManager : TrackManager + public class PreviewTrackManager : Component { - private AudioManager audio; - private Track currentTrack; - private readonly BindableDouble muteBindable; + public event Action PlaybackStarted; + public event Action PlaybackStopped; - public PreviewTrackManager() - : base(new OnlineStore()) - { - muteBindable = new BindableDouble(); - } + private TrackManager trackManager; + private BindableDouble muteBindable; + + public Track CurrentTrack { get; private set; } [BackgroundDependencyLoader] private void load(AudioManager audio, FrameworkConfigManager config) { - this.audio = audio; + trackManager = new TrackManager(new OnlineStore()); - audio.AddItem(this); + muteBindable = new BindableDouble(); - config.BindWith(FrameworkSetting.VolumeMusic, Volume); + audio.AddItem(trackManager); + config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); + + PlaybackStarted += () => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + PlaybackStopped += () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); } - protected override void UpdateState() - { - if (currentTrack?.HasCompleted ?? false) - onStop(); + public Track Get(BeatmapSetInfo beatmapSetInfo) => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"); - base.UpdateState(); + protected override void Update() + { + if (CurrentTrack?.HasCompleted ?? false) + PlaybackStopped?.Invoke(); + + base.Update(); } public void Play(Track track) { - currentTrack?.Stop(); - currentTrack = track; - currentTrack.Restart(); - onPlay(); + Stop(); + CurrentTrack = track; + track.Restart(); + PlaybackStarted?.Invoke(); } - private void onPlay() => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - public void Stop() { - currentTrack?.Stop(); - onStop(); + if (CurrentTrack?.IsRunning ?? false) + { + CurrentTrack?.Stop(); + PlaybackStopped?.Invoke(); + } } - - private void onStop() => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); } } From c492f62edaac7b92d505c8d0eaf5fa2112522e4e Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 9 May 2018 14:52:46 +0300 Subject: [PATCH 005/186] Use PreviewTrackManager in the PlayButton --- osu.Game/OsuGameBase.cs | 5 ++ osu.Game/Overlays/Direct/PlayButton.cs | 112 +++++-------------------- 2 files changed, 24 insertions(+), 93 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 487cb50c9a..4d2d4d05a7 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -23,6 +23,7 @@ using osu.Game.Online.API; using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Textures; using osu.Framework.Logging; +using osu.Game.Audio; using osu.Game.Database; using osu.Game.Graphics.Textures; using osu.Game.Input; @@ -202,6 +203,10 @@ namespace osu.Game KeyBindingStore.Register(globalBinding); dependencies.Cache(globalBinding); + + PreviewTrackManager previewTrackManager; + dependencies.Cache(previewTrackManager = new PreviewTrackManager()); + Add(previewTrackManager); } private void runMigrations() diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index dae3b63a8f..082cf34d8e 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -1,24 +1,22 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Allocation; -using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; -using osu.Framework.IO.Stores; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK.Graphics; namespace osu.Game.Overlays.Direct { public class PlayButton : Container { - private static PlayButton activeBeatmapPreview; public readonly Bindable Playing = new Bindable(); public Track Preview { get; private set; } @@ -33,17 +31,16 @@ namespace osu.Game.Overlays.Direct beatmapSet = value; Playing.Value = false; - trackLoader = null; Preview = null; } } + private PreviewTrackManager previewTrackManager; + private Color4 hoverColour; private readonly SpriteIcon icon; private readonly LoadingAnimation loadingAnimation; - private readonly BindableDouble muteBindable = new BindableDouble(); - private const float transition_duration = 500; private bool loading @@ -79,14 +76,20 @@ namespace osu.Game.Overlays.Direct loadingAnimation = new LoadingAnimation(), }); - Playing.ValueChanged += updatePreviewTrack; + Playing.ValueChanged += playingStateChanged; } [BackgroundDependencyLoader] - private void load(OsuColour colour, AudioManager audio) + private void load(OsuColour colour, PreviewTrackManager previewTrackManager) { hoverColour = colour.Yellow; - this.audio = audio; + this.previewTrackManager = previewTrackManager; + + previewTrackManager.PlaybackStopped += () => + { + if (Preview == previewTrackManager.CurrentTrack) + Playing.Value = false; + }; } protected override bool OnClick(InputState state) @@ -108,18 +111,7 @@ namespace osu.Game.Overlays.Direct base.OnHoverLost(state); } - protected override void Update() - { - base.Update(); - - if (Preview?.HasCompleted ?? false) - { - Playing.Value = false; - Preview = null; - } - } - - private void updatePreviewTrack(bool playing) + private void playingStateChanged(bool playing) { if (playing && BeatmapSet == null) { @@ -132,25 +124,18 @@ namespace osu.Game.Overlays.Direct if (playing) { - if (activeBeatmapPreview != null) - activeBeatmapPreview.Playing.Value = false; - if (Preview == null) { - beginAudioLoad(); - return; + loading = true; + Preview = previewTrackManager.Get(beatmapSet); + loading = false; } - Preview.Restart(); - - audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - activeBeatmapPreview = this; + previewTrackManager.Play(Preview); } else { - audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); - - Preview?.Stop(); + previewTrackManager.Stop(); loading = false; } } @@ -160,64 +145,5 @@ namespace osu.Game.Overlays.Direct base.Dispose(isDisposing); Playing.Value = false; } - - private TrackLoader trackLoader; - private AudioManager audio; - - private void beginAudioLoad() - { - if (trackLoader != null) - { - Preview = trackLoader.Preview; - Playing.TriggerChange(); - return; - } - - loading = true; - - LoadComponentAsync(trackLoader = new TrackLoader($"https://b.ppy.sh/preview/{BeatmapSet.OnlineBeatmapSetID}.mp3"), - d => - { - // We may have been replaced by another loader - if (trackLoader != d) return; - - Preview = d?.Preview; - updatePreviewTrack(Playing); - loading = false; - - Add(trackLoader); - }); - } - - private class TrackLoader : Drawable - { - private readonly string preview; - - public Track Preview; - private TrackManager trackManager; - - public TrackLoader(string preview) - { - this.preview = preview; - } - - [BackgroundDependencyLoader] - private void load(AudioManager audio, FrameworkConfigManager config) - { - // create a local trackManager to bypass the mute we are applying above. - audio.AddItem(trackManager = new TrackManager(new OnlineStore())); - - // add back the user's music volume setting (since we are no longer in the global TrackManager's hierarchy). - config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); - - Preview = trackManager.Get(preview); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - trackManager?.Dispose(); - } - } } } From 95dd2125ee91dbda04d527d1c34d236a9190c1f9 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Wed, 9 May 2018 16:22:52 +0300 Subject: [PATCH 006/186] Load PlayButton.Preview asynchronously --- osu.Game/Overlays/Direct/PlayButton.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 082cf34d8e..77c904050b 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Configuration; @@ -126,9 +127,17 @@ namespace osu.Game.Overlays.Direct { if (Preview == null) { - loading = true; - Preview = previewTrackManager.Get(beatmapSet); - loading = false; + Task.Run(() => + { + loading = true; + return Preview = previewTrackManager.Get(beatmapSet); + }) + .ContinueWith(t => + { + playingStateChanged(true); + loading = false; + }); + return; } previewTrackManager.Play(Preview); From 95a207ef56a9907fff4c892f7e36c47fbf6e843d Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 00:17:42 +0200 Subject: [PATCH 007/186] Fixed the parallax background missing from the space occupied by the top toolbar. --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 32161a0b8e..38dbf1a65d 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,7 +160,7 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale / overscan), + Scale = new Vector2(1 / circle_outer_scale), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From ca05fde14c7c9f984caf6c7fcbbdbe3ce78ed010 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 00:47:03 +0200 Subject: [PATCH 008/186] Fix the Parallax Background not filling the entire Circle Container. --- osu.Game/Screens/Ranking/Results.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 38dbf1a65d..a2990d7902 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -159,8 +159,11 @@ namespace osu.Game.Screens.Ranking backgroundParallax = new ParallaxContainer { RelativeSizeAxes = Axes.Both, - ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale), + ParallaxAmount = 0.02f, + //Compensate for the Toolbar + Scale = new Vector2(1.06f / circle_outer_scale / overscan), + //Offset the background to account for the toolbar. + Position = new Vector2(0, -20), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From be56d8cb8253a7c710579f54377f5563e9c01170 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 00:53:31 +0200 Subject: [PATCH 009/186] Change the parallax amount --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index a2990d7902..17e8666ebf 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Ranking backgroundParallax = new ParallaxContainer { RelativeSizeAxes = Axes.Both, - ParallaxAmount = 0.02f, + ParallaxAmount = 0.01f, //Compensate for the Toolbar Scale = new Vector2(1.06f / circle_outer_scale / overscan), //Offset the background to account for the toolbar. From be1159444d2fb9cb15f0019b275fa9f6a6df48e4 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Tue, 15 May 2018 15:56:49 +0200 Subject: [PATCH 010/186] Use the absolute value of ParallaxAmount to make sure we're not scaling stuff down when using a negative ParallaxAmount --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index dc635ce7e7..51be40c1e8 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers if (!parallaxEnabled) { content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + ParallaxAmount); + content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); } }; } @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); } firstUpdate = false; From 1e88f216f27831a8c5bc76cf09ce271be61e0580 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:27:18 +0200 Subject: [PATCH 011/186] Revert the ParallaxContainer changes I made by accident back. --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 4 ++-- osu.Game/Screens/Ranking/Results.cs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index 51be40c1e8..dc635ce7e7 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers if (!parallaxEnabled) { content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); + content.Scale = new Vector2(1 + ParallaxAmount); } }; } @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); } firstUpdate = false; diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 17e8666ebf..32161a0b8e 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,10 +160,7 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - //Compensate for the Toolbar - Scale = new Vector2(1.06f / circle_outer_scale / overscan), - //Offset the background to account for the toolbar. - Position = new Vector2(0, -20), + Scale = new Vector2(1 / circle_outer_scale / overscan), Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] From 428d0f5deec85cfb2153d8246301f3f269865346 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:30:16 +0200 Subject: [PATCH 012/186] Re-implement the fix after it got deleted in the previous commit. --- osu.Game/Screens/Ranking/Results.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 32161a0b8e..162c428444 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,8 +160,11 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - Scale = new Vector2(1 / circle_outer_scale / overscan), + //Compensate for the Toolbar + Scale = new Vector2(1.06f / circle_outer_scale / overscan), + //Offset the background to account for the toolbar. Anchor = Anchor.Centre, + Position = new Vector2(0, -20), Origin = Anchor.Centre, Children = new Drawable[] { From 3b708f650591a015ccd1e54721981f4316fbce4b Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:34:08 +0200 Subject: [PATCH 013/186] make it equal with the original codebase. --- osu.Game/Screens/Ranking/Results.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 162c428444..67949f8e14 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -160,17 +160,14 @@ namespace osu.Game.Screens.Ranking { RelativeSizeAxes = Axes.Both, ParallaxAmount = 0.01f, - //Compensate for the Toolbar - Scale = new Vector2(1.06f / circle_outer_scale / overscan), - //Offset the background to account for the toolbar. + Scale = new Vector2(1 / circle_outer_scale / overscan), Anchor = Anchor.Centre, - Position = new Vector2(0, -20), Origin = Anchor.Centre, Children = new Drawable[] { new Sprite { - RelativeSizeAxes = Axes.Both, + RelativeSsizeAxes = Axes.Both, Alpha = 0.2f, Texture = Beatmap.Value.Background, Anchor = Anchor.Centre, From 705960dabbc32591ccd36841e66e101e41133189 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:36:26 +0200 Subject: [PATCH 014/186] Fix typo --- osu.Game/Screens/Ranking/Results.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Results.cs b/osu.Game/Screens/Ranking/Results.cs index 67949f8e14..32161a0b8e 100644 --- a/osu.Game/Screens/Ranking/Results.cs +++ b/osu.Game/Screens/Ranking/Results.cs @@ -167,7 +167,7 @@ namespace osu.Game.Screens.Ranking { new Sprite { - RelativeSsizeAxes = Axes.Both, + RelativeSizeAxes = Axes.Both, Alpha = 0.2f, Texture = Beatmap.Value.Background, Anchor = Anchor.Centre, From d2b2d3e2e078de26188030f79c1722e2f30d2589 Mon Sep 17 00:00:00 2001 From: KoziLord Date: Wed, 16 May 2018 01:38:46 +0200 Subject: [PATCH 015/186] Use the absolute value of ParallaxAmount to make sure we're not scaling things down when using a negative value for the Parallax (moving against the cursor instead of with it) --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index dc635ce7e7..51be40c1e8 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers if (!parallaxEnabled) { content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + ParallaxAmount); + content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); } }; } @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + ParallaxAmount), 0, 1000, Easing.OutQuint); + content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); } firstUpdate = false; From 79c64d16e43da33e3e21fdcefdd192da9eaba2b7 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:49:23 +0800 Subject: [PATCH 016/186] Realization on Catch Star Rating --- .../Difficulty/CatchDifficultyCalculator.cs | 160 +++++++++++++++++- .../Difficulty/CatchDifficultyHitObject.cs | 127 ++++++++++++++ 2 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index f8351b7519..5351bd746d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -1,18 +1,174 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { - public CatchDifficultyCalculator(IBeatmap beatmap) : base(beatmap) + private const double STAR_SCALING_FACTOR = 0.145; + private const float PLAYFIELD_WIDTH = CatchPlayfield.BASE_WIDTH; + + private readonly List difficultyHitObjects = new List(); + + public CatchDifficultyCalculator(IBeatmap beatmap) + : base(beatmap) { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + public CatchDifficultyCalculator(IBeatmap beatmap, Mod[] mods) + : base(beatmap, mods) + { + } + + public override double Calculate(Dictionary categoryDifficulty = null) + { + + difficultyHitObjects.Clear(); + + float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; + float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * 172; + //float catcherWidth = (float)(305.0f / 1.6f * ((102.4f * (1.0f - 0.7 * (circleSize - 5.0f)) / 5.0f) / 128.0f * 0.7f)); + float catcherWidthHalf = catcherWidth / 2; + catcherWidthHalf *= 0.8f; + + foreach (var hitObject in Beatmap.HitObjects) + { + // We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations. + if (hitObject is Fruit) + { + difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, catcherWidthHalf)); + } + if (hitObject is JuiceStream) + { + IEnumerator nestedHitObjectsEnumerator = hitObject.NestedHitObjects.GetEnumerator(); + while (nestedHitObjectsEnumerator.MoveNext()) + { + CatchHitObject objectInJuiceStream = (CatchHitObject)nestedHitObjectsEnumerator.Current; + if (!(objectInJuiceStream is TinyDroplet)) + difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, catcherWidthHalf)); + } + } + } + + difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); + + if (!CalculateStrainValues()) return 0; + + double starRating = Math.Sqrt(CalculateDifficulty()) * STAR_SCALING_FACTOR; + + if (categoryDifficulty != null) + { + categoryDifficulty["Aim"] = starRating; + + double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; + double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; + + categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; + + //categoryDifficulty.Add("AR", (preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0).ToString("0.00", GameBase.nfi)); + //categoryDifficulty.Add("Max combo", DifficultyHitObjects.Count.ToString(GameBase.nfi)); + } + + return starRating; + } + + protected bool CalculateStrainValues() + { + // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. + using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + { + + if (!hitObjectsEnumerator.MoveNext()) return false; + + CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; + CatchDifficultyHitObject nextHitObject; + + // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject. + while (hitObjectsEnumerator.MoveNext()) + { + nextHitObject = hitObjectsEnumerator.Current; + nextHitObject.CalculateStrains(currentHitObject, TimeRate); + currentHitObject = nextHitObject; + } + + return true; + } + } + + /// + /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP. + /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. + /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. + /// + protected const double STRAIN_STEP = 750; + + /// + /// The weighting of each strain value decays to this number * it's previous value + /// + protected const double DECAY_WEIGHT = 0.94; + + protected double CalculateDifficulty() + { + // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods + double actualStrainStep = STRAIN_STEP * TimeRate; + + // Find the highest strain value within each strain step + List highestStrains = new List(); + double intervalEndTime = actualStrainStep; + double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval + + CatchDifficultyHitObject previousHitObject = null; + foreach (CatchDifficultyHitObject hitObject in difficultyHitObjects) + { + // While we are beyond the current interval push the currently available maximum to our strain list + while (hitObject.BaseHitObject.StartTime > intervalEndTime) + { + highestStrains.Add(maximumStrain); + + // The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay + // until the beginning of the next interval. + if (previousHitObject == null) + { + maximumStrain = 0; + } + else + { + double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + maximumStrain = previousHitObject.Strain * decay; + } + + // Go to the next time interval + intervalEndTime += actualStrainStep; + } + + // Obtain maximum strain + maximumStrain = Math.Max(hitObject.Strain, maximumStrain); + + previousHitObject = hitObject; + } + + + // Build the weighted sum over the highest strains for each interval + double difficulty = 0; + double weight = 1; + highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. + + foreach (double strain in highestStrains) + { + difficulty += weight * strain; + weight *= DECAY_WEIGHT; + } + + return difficulty; + } } } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs new file mode 100644 index 0000000000..14f9445c75 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -0,0 +1,127 @@ +using System; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using OpenTK; + +namespace osu.Game.Rulesets.Catch.Difficulty +{ + class CatchDifficultyHitObject + { + internal static readonly double DECAY_BASE = 0.20; + private const float NORMALIZED_HITOBJECT_RADIUS = 41.0f; + private const float ABSOLUTE_PLAYER_POSITIONING_ERROR = 16f; + private float playerPositioningError; + + internal CatchHitObject BaseHitObject; + + /// + /// Measures jump difficulty. CtB doesn't have something like button pressing speed or accuracy + /// + internal double Strain = 1; + + /// + /// This is required to keep track of lazy player movement (always moving only as far as necessary) + /// Without this quick repeat sliders / weirdly shaped streams might become ridiculously overrated + /// + internal float PlayerPositionOffset; + internal float LastMovement; + + internal float NormalizedPosition; + internal float ActualNormalizedPosition => NormalizedPosition + PlayerPositionOffset; + + internal CatchDifficultyHitObject(CatchHitObject baseHitObject, float catcherWidthHalf) + { + BaseHitObject = baseHitObject; + + // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. + float scalingFactor = NORMALIZED_HITOBJECT_RADIUS / catcherWidthHalf; + + playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR;// * scalingFactor; + NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor; + } + + private const double DIRECTION_CHANGE_BONUS = 12.5; + internal void CalculateStrains(CatchDifficultyHitObject previousHitObject, double timeRate) + { + // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. + // See Taiko feedback thread. + double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; + double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000); + + // Update new position with lazy movement. + PlayerPositionOffset = + MathHelper.Clamp( + previousHitObject.ActualNormalizedPosition, + NormalizedPosition - (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError), + NormalizedPosition + (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. + - NormalizedPosition; // Subtract HitObject position to obtain offset + + LastMovement = DistanceTo(previousHitObject); + double addition = spacingWeight(LastMovement); + + if (NormalizedPosition < previousHitObject.NormalizedPosition) + { + LastMovement = -LastMovement; + } + + CatchHitObject previousHitCircle = previousHitObject.BaseHitObject; + + double additionBonus = 0; + double sqrtTime = Math.Sqrt(Math.Max(timeElapsed, 25)); + + // Direction changes give an extra point! + if (Math.Abs(LastMovement) > 0.1) + { + if (Math.Abs(previousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(previousHitObject.LastMovement)) + { + double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; + + // Weight bonus by how + double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; + + // We want time to play a role twice here! + addition += bonus * bonusFactor; + + // Bonus for tougher direction switches and "almost" hyperdashes at this point + if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH) + { + additionBonus += 0.3 * bonusFactor; + } + } + + // Base bonus for every movement, giving some weight to streams. + addition += 7.5 * Math.Min(Math.Abs(LastMovement), NORMALIZED_HITOBJECT_RADIUS * 2) / (NORMALIZED_HITOBJECT_RADIUS * 6) / sqrtTime; + } + + // Bonus for "almost" hyperdashes at corner points + if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH) + { + if (!previousHitCircle.HyperDash) + { + additionBonus += 1.0; + } + else + { + // After a hyperdash we ARE in the correct position. Always! + PlayerPositionOffset = 0; + } + + addition *= 1.0 + additionBonus * ((10 - previousHitCircle.DistanceToHyperDash * CatchPlayfield.BASE_WIDTH) / 10); + } + + addition *= 850.0 / Math.Max(timeElapsed, 25); + + Strain = previousHitObject.Strain * decay + addition; + } + + private static double spacingWeight(float distance) + { + return Math.Pow(distance, 1.3) / 500; + } + + internal float DistanceTo(CatchDifficultyHitObject other) + { + return Math.Abs(ActualNormalizedPosition - other.ActualNormalizedPosition); + } + } +} From 6bf5ea73d5f19ba4d706f9754a7169c5ae8e5f8e Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:53:20 +0800 Subject: [PATCH 017/186] Fix CatcherWidth --- .../Difficulty/CatchDifficultyCalculator.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 5351bd746d..59c512c469 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -35,8 +35,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * 172; - //float catcherWidth = (float)(305.0f / 1.6f * ((102.4f * (1.0f - 0.7 * (circleSize - 5.0f)) / 5.0f) / 128.0f * 0.7f)); + float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; From 0ef718a09e6269343b6a3a04b1b3f9bfaaaf7d3a Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:55:07 +0800 Subject: [PATCH 018/186] Fixes on categoryDifficulty --- .../Difficulty/CatchDifficultyCalculator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 59c512c469..63570d44b0 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -72,9 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; - - //categoryDifficulty.Add("AR", (preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0).ToString("0.00", GameBase.nfi)); - //categoryDifficulty.Add("Max combo", DifficultyHitObjects.Count.ToString(GameBase.nfi)); + categoryDifficulty["Max combo"] = difficultyHitObjects.Count; } return starRating; From 44fd4b95bd7ce7c7ec58e6dc82cd57f5447ac2b1 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 09:58:46 +0800 Subject: [PATCH 019/186] We need DistanceToHyperDash for star rating calculation --- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 548813fbd2..d55cdac115 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -24,6 +24,11 @@ namespace osu.Game.Rulesets.Catch.Objects public int ComboIndex { get; set; } + /// + /// The distance for a fruit to to next hyper if it's not a hyper. + /// + public float DistanceToHyperDash { get; set; } + /// /// The next fruit starts a new combo. Used for explodey. /// From 0405383e4e3eb352b2e78e428ab473f00e69fca6 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:12:18 +0800 Subject: [PATCH 020/186] Fixing code style --- .../Difficulty/CatchDifficultyCalculator.cs | 21 +++++-------------- .../Difficulty/CatchDifficultyHitObject.cs | 2 +- .../Difficulty/TaikoDifficultyCalculator.cs | 12 ++--------- .../Difficulty/DifficultyCalculator.cs | 15 +++++++++++++ 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 63570d44b0..83b5b3bb5c 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty public override double Calculate(Dictionary categoryDifficulty = null) { - difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; @@ -83,7 +82,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) { - if (!hitObjectsEnumerator.MoveNext()) return false; CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; @@ -106,17 +104,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. /// - protected const double STRAIN_STEP = 750; + protected const double strain_step = 750; /// /// The weighting of each strain value decays to this number * it's previous value /// - protected const double DECAY_WEIGHT = 0.94; + protected const double decay_weight = 0.94; protected double CalculateDifficulty() { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods - double actualStrainStep = STRAIN_STEP * TimeRate; + double actualStrainStep = strain_step * TimeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -153,17 +151,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty previousHitObject = hitObject; } - - // Build the weighted sum over the highest strains for each interval - double difficulty = 0; - double weight = 1; - highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. - - foreach (double strain in highestStrains) - { - difficulty += weight * strain; - weight *= DECAY_WEIGHT; - } + // calculate maximun strain difficulty + double difficulty = StrainCalculator(highestStrains, decay_weight); return difficulty; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 14f9445c75..f4eefdd7cd 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. float scalingFactor = NORMALIZED_HITOBJECT_RADIUS / catcherWidthHalf; - playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR;// * scalingFactor; + playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR; // * scalingFactor; NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 57e1e65064..197464c10a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -122,16 +122,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty previousHitObject = hitObject; } - // Build the weighted sum over the highest strains for each interval - double difficulty = 0; - double weight = 1; - highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. - - foreach (double strain in highestStrains) - { - difficulty += weight * strain; - weight *= decay_weight; - } + // calculate maximun strain difficulty + double difficulty = StrainCalculator(highestStrains, decay_weight); return difficulty; } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 070bc7ddb0..348435b0d0 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -37,5 +37,20 @@ namespace osu.Game.Rulesets.Difficulty } public abstract double Calculate(Dictionary categoryDifficulty = null); + + protected double StrainCalculator(List highestStrains, double decayWeight) + { + // Build the weighted sum over the highest strains for each interval + double difficulty = 0; + double weight = 1; + highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain. + + foreach (double strain in highestStrains) + { + difficulty += weight * strain; + weight *= decayWeight; + } + return difficulty; + } } } From 886be8ce1f7c29d558e3a34f42863740c7ca6515 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:16:32 +0800 Subject: [PATCH 021/186] Adding lisence header --- .../Difficulty/CatchDifficultyCalculator.cs | 2 +- .../Difficulty/CatchDifficultyHitObject.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 83b5b3bb5c..19d1bab0ac 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty return true; } } - + /// /// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP. /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index f4eefdd7cd..778ab9df28 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using OpenTK; @@ -76,7 +79,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; - // Weight bonus by how + // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! From 68a929eb0c1d78e38687f55b42b61c05d6a1e9a1 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:39:16 +0800 Subject: [PATCH 022/186] Fixing parameters naming --- .../Difficulty/CatchDifficultyCalculator.cs | 17 +++++------ .../Difficulty/CatchDifficultyHitObject.cs | 28 +++++++++---------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 19d1bab0ac..31de9cfc8d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -14,8 +14,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { - private const double STAR_SCALING_FACTOR = 0.145; - private const float PLAYFIELD_WIDTH = CatchPlayfield.BASE_WIDTH; + private const double star_scaling_factor = 0.145; + private const float playfield_width = CatchPlayfield.BASE_WIDTH; private readonly List difficultyHitObjects = new List(); @@ -54,6 +54,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!(objectInJuiceStream is TinyDroplet)) difficultyHitObjects.Add(new CatchDifficultyHitObject(objectInJuiceStream, catcherWidthHalf)); } + // Dispose the enumerator after counting all fruits. + nestedHitObjectsEnumerator.Dispose(); } } @@ -61,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!CalculateStrainValues()) return 0; - double starRating = Math.Sqrt(CalculateDifficulty()) * STAR_SCALING_FACTOR; + double starRating = Math.Sqrt(CalculateDifficulty()) * star_scaling_factor; if (categoryDifficulty != null) { @@ -85,12 +87,11 @@ namespace osu.Game.Rulesets.Catch.Difficulty if (!hitObjectsEnumerator.MoveNext()) return false; CatchDifficultyHitObject currentHitObject = hitObjectsEnumerator.Current; - CatchDifficultyHitObject nextHitObject; // First hitObject starts at strain 1. 1 is the default for strain values, so we don't need to set it here. See DifficultyHitObject. while (hitObjectsEnumerator.MoveNext()) { - nextHitObject = hitObjectsEnumerator.Current; + CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; nextHitObject.CalculateStrains(currentHitObject, TimeRate); currentHitObject = nextHitObject; } @@ -104,12 +105,12 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain. /// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage. /// - protected const double strain_step = 750; + private const double strain_step = 750; /// /// The weighting of each strain value decays to this number * it's previous value /// - protected const double decay_weight = 0.94; + private const double decay_weight = 0.94; protected double CalculateDifficulty() { @@ -137,7 +138,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty } else { - double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + double decay = Math.Pow(CatchDifficultyHitObject.decay_base, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); maximumStrain = previousHitObject.Strain * decay; } diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 778ab9df28..190c92b319 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -8,12 +8,12 @@ using OpenTK; namespace osu.Game.Rulesets.Catch.Difficulty { - class CatchDifficultyHitObject + internal class CatchDifficultyHitObject { - internal static readonly double DECAY_BASE = 0.20; - private const float NORMALIZED_HITOBJECT_RADIUS = 41.0f; - private const float ABSOLUTE_PLAYER_POSITIONING_ERROR = 16f; - private float playerPositioningError; + internal static readonly double decay_base = 0.20; + private const float normalized_hitobject_radius = 41.0f; + private const float absolute_player_positioning_error = 16f; + private readonly float playerPositioningError; internal CatchHitObject BaseHitObject; @@ -37,26 +37,26 @@ namespace osu.Game.Rulesets.Catch.Difficulty BaseHitObject = baseHitObject; // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. - float scalingFactor = NORMALIZED_HITOBJECT_RADIUS / catcherWidthHalf; + float scalingFactor = normalized_hitobject_radius / catcherWidthHalf; - playerPositioningError = ABSOLUTE_PLAYER_POSITIONING_ERROR; // * scalingFactor; + playerPositioningError = absolute_player_positioning_error; // * scalingFactor; NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor; } - private const double DIRECTION_CHANGE_BONUS = 12.5; + private const double direction_change_bonus = 12.5; internal void CalculateStrains(CatchDifficultyHitObject previousHitObject, double timeRate) { // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. // See Taiko feedback thread. double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; - double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000); + double decay = Math.Pow(decay_base, timeElapsed / 1000); // Update new position with lazy movement. PlayerPositionOffset = MathHelper.Clamp( previousHitObject.ActualNormalizedPosition, - NormalizedPosition - (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError), - NormalizedPosition + (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. + NormalizedPosition - (normalized_hitobject_radius - playerPositioningError), + NormalizedPosition + (normalized_hitobject_radius - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. - NormalizedPosition; // Subtract HitObject position to obtain offset LastMovement = DistanceTo(previousHitObject); @@ -77,9 +77,9 @@ namespace osu.Game.Rulesets.Catch.Difficulty { if (Math.Abs(previousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(previousHitObject.LastMovement)) { - double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; + double bonus = direction_change_bonus / sqrtTime; - // Weight bonus by how + // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty } // Base bonus for every movement, giving some weight to streams. - addition += 7.5 * Math.Min(Math.Abs(LastMovement), NORMALIZED_HITOBJECT_RADIUS * 2) / (NORMALIZED_HITOBJECT_RADIUS * 6) / sqrtTime; + addition += 7.5 * Math.Min(Math.Abs(LastMovement), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtTime; } // Bonus for "almost" hyperdashes at corner points From 871743204b00983179fff782745cdea1bf341b5a Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 10:41:58 +0800 Subject: [PATCH 023/186] Fixing parameters naming --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index 190c92b319..d9b16c2a0b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { double bonus = direction_change_bonus / sqrtTime; - // Weight bonus by how + // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! From 2e5bc4323ad553b8f85fef881b552b8e8c9e956d Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:31:00 +0800 Subject: [PATCH 024/186] Fixing null reference exception bugs --- .../Difficulty/CatchDifficultyCalculator.cs | 9 +++++---- .../Difficulty/CatchDifficultyHitObject.cs | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 31de9cfc8d..2fa946f41c 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; + float catcherWidth = ((1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f) * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; - categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; + categoryDifficulty["AR"] = (preEmpt > 1200.0) ? -(preEmpt - 1800.0) / 120.0 : (-(preEmpt - 1200.0) / 150.0) + 5.0; categoryDifficulty["Max combo"] = difficultyHitObjects.Count; } @@ -92,7 +92,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty while (hitObjectsEnumerator.MoveNext()) { CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; - nextHitObject.CalculateStrains(currentHitObject, TimeRate); + if (nextHitObject != null) + nextHitObject.CalculateStrains(currentHitObject, TimeRate); currentHitObject = nextHitObject; } @@ -111,7 +112,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// The weighting of each strain value decays to this number * it's previous value /// private const double decay_weight = 0.94; - + protected double CalculateDifficulty() { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs index d9b16c2a0b..72fc6d211b 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyHitObject.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty { internal class CatchDifficultyHitObject { - internal static readonly double decay_base = 0.20; + internal static readonly double DECAY_BASE = 0.20; private const float normalized_hitobject_radius = 41.0f; private const float absolute_player_positioning_error = 16f; private readonly float playerPositioningError; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. // See Taiko feedback thread. double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; - double decay = Math.Pow(decay_base, timeElapsed / 1000); + double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000); // Update new position with lazy movement. PlayerPositionOffset = From 6d71f7f220940eb8bcc2750dd3e192b85fa6e777 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:35:02 +0800 Subject: [PATCH 025/186] Minor fixes --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 2fa946f41c..beee332504 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty /// The weighting of each strain value decays to this number * it's previous value /// private const double decay_weight = 0.94; - + protected double CalculateDifficulty() { // The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods From 193a29860144f3e5c41b8b09c5492271ff07a2fd Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:36:57 +0800 Subject: [PATCH 026/186] Fixing minor bugs --- osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index beee332504..43c157df06 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -139,7 +139,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty } else { - double decay = Math.Pow(CatchDifficultyHitObject.decay_base, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); maximumStrain = previousHitObject.Strain * decay; } From 4784538d7349a2e1fcef059141c992524a2e2bd6 Mon Sep 17 00:00:00 2001 From: frankhjwx Date: Mon, 21 May 2018 13:53:48 +0800 Subject: [PATCH 027/186] Fixing minor bugs --- osu-framework | 2 +- .../Difficulty/CatchDifficultyCalculator.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu-framework b/osu-framework index 80e78fd45b..fac688633b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 80e78fd45bb79ca4bc46ecc05deb6058f3879faa +Subproject commit fac688633b8fcf34ae5d0514c26b03e217161eb4 diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 43c157df06..975e8eed58 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty difficultyHitObjects.Clear(); float circleSize = Beatmap.BeatmapInfo.BaseDifficulty.CircleSize; - float catcherWidth = ((1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f) * CatcherArea.CATCHER_SIZE; + float catcherWidth = (1.0f - 0.7f * (circleSize - 5) / 5) * 0.62064f * CatcherArea.CATCHER_SIZE; float catcherWidthHalf = catcherWidth / 2; catcherWidthHalf *= 0.8f; @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate; double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450) / TimeRate; - categoryDifficulty["AR"] = (preEmpt > 1200.0) ? -(preEmpt - 1800.0) / 120.0 : (-(preEmpt - 1200.0) / 150.0) + 5.0; + categoryDifficulty["AR"] = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0; categoryDifficulty["Max combo"] = difficultyHitObjects.Count; } @@ -92,8 +92,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty while (hitObjectsEnumerator.MoveNext()) { CatchDifficultyHitObject nextHitObject = hitObjectsEnumerator.Current; - if (nextHitObject != null) - nextHitObject.CalculateStrains(currentHitObject, TimeRate); + nextHitObject?.CalculateStrains(currentHitObject, TimeRate); currentHitObject = nextHitObject; } From 49f893d5e42b3712a7801ea329128bb2701538dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 12:00:11 +0900 Subject: [PATCH 028/186] Couple the timeline to the audio --- .../Visual/TestCaseEditorComposeTimeline.cs | 13 ++- .../Edit/Screens/Compose/Timeline/Timeline.cs | 80 +++++++++++++++++++ 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 0776bc123e..aff7abe03d 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -14,14 +14,15 @@ using osu.Game.Screens.Edit.Screens.Compose.Timeline; namespace osu.Game.Tests.Visual { [TestFixture] - public class TestCaseEditorComposeTimeline : OsuTestCase + public class TestCaseEditorComposeTimeline : EditorClockTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(BeatmapWaveformGraph), typeof(TimelineButton) }; - private readonly TimelineArea timelineArea; - - public TestCaseEditorComposeTimeline() + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) { + TimelineArea timelineArea; + Children = new Drawable[] { new MusicController @@ -38,11 +39,7 @@ namespace osu.Game.Tests.Visual Size = new Vector2(0.8f, 100) } }; - } - [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame) - { timelineArea.Beatmap.BindTo(osuGame.Beatmap); } } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 9801ba12a1..e8d34b466c 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -1,8 +1,11 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Input; +using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -13,6 +16,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline public readonly Bindable WaveformVisible = new Bindable(); public readonly Bindable Beatmap = new Bindable(); + private IAdjustableClock adjustableClock; + public Timeline() { ZoomDuration = 200; @@ -32,12 +37,87 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); } + [BackgroundDependencyLoader] + private void load(IAdjustableClock adjustableClock) + { + this.adjustableClock = adjustableClock; + } + + private bool handlingUserInput; + private bool trackWasPlaying; + protected override void Update() { base.Update(); // We want time = 0 to be at the centre of the container when scrolled to the start Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; + + if (!handlingUserInput) + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + else + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + if (base.OnMouseDown(state, args)) + { + beginUserInput(); + return true; + } + + return false; + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + endUserInput(); + return base.OnMouseUp(state, args); + } + + private void beginUserInput() + { + handlingUserInput = true; + trackWasPlaying = adjustableClock.IsRunning; + adjustableClock.Stop(); + } + + private void endUserInput() + { + handlingUserInput = false; + if (trackWasPlaying) + adjustableClock.Start(); + } + + protected override ScrollbarContainer CreateScrollbar(Direction direction) => new TimelineScrollbar(this, direction); + + private class TimelineScrollbar : ScrollbarContainer + { + private readonly Timeline timeline; + + public TimelineScrollbar(Timeline timeline, Direction scrollDir) + : base(scrollDir) + { + this.timeline = timeline; + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + if (base.OnMouseDown(state, args)) + { + timeline.beginUserInput(); + return true; + } + + return false; + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + timeline.endUserInput(); + return base.OnMouseUp(state, args); + } } } } From f18677382c59446d4cdc307ed5969c5a4c2b71f7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 12:00:23 +0900 Subject: [PATCH 029/186] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 8f007de13e..907265b750 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 8f007de13e4a1aed46cb35e5018448f809bd5e88 +Subproject commit 907265b7501964a09eb2cd89ec2257941183c65c From 6b0eeb343651bd50764199b3413c59dd946ae2df Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 14:14:32 +0900 Subject: [PATCH 030/186] Rework seeking interactions to support smooth scrolling --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index e8d34b466c..9dbaa1586d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -43,20 +43,59 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline this.adjustableClock = adjustableClock; } - private bool handlingUserInput; + /// + /// The track's time in the previous frame. + /// + private double lastTrackTime; + + /// + /// Whether the user is currently dragging the timeline. + /// + private bool handlingDragInput; + + /// + /// Whether the track was playing before a user drag event. + /// private bool trackWasPlaying; protected override void Update() { base.Update(); - // We want time = 0 to be at the centre of the container when scrolled to the start + // The extrema of track time should be positioned at the centre of the container when scrolled to the start or end Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 }; - if (!handlingUserInput) - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); - else + if (handlingDragInput) + { + // The user is dragging - the track should always follow the timeline adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + else if (adjustableClock.IsRunning) + { + // If the user hasn't provided mouse input but the track is running, always follow the track + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + } + else + { + // The track isn't playing, so we want to smooth-scroll once more, and re-enable wheel scrolling + // There are two cases we have to be wary of: + // 1) The user scrolls on this timeline: We want the track to follow us + // 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time + + // The simplest way to cover both cases is by checking that inter-frame track times are identical + if (adjustableClock.CurrentTime == lastTrackTime) + { + // The track hasn't been seeked externally + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + else + { + // The track has been seeked externally + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + } + } + + lastTrackTime = adjustableClock.CurrentTime; } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) @@ -78,14 +117,14 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private void beginUserInput() { - handlingUserInput = true; + handlingDragInput = true; trackWasPlaying = adjustableClock.IsRunning; adjustableClock.Stop(); } private void endUserInput() { - handlingUserInput = false; + handlingDragInput = false; if (trackWasPlaying) adjustableClock.Start(); } From a30f72b477d6353d0e785d94cd66aac6fefe50de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 23 May 2018 14:32:00 +0900 Subject: [PATCH 031/186] Add helper methods for seeking/scrolling --- .../Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 9dbaa1586d..df615ad035 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -68,12 +68,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (handlingDragInput) { // The user is dragging - the track should always follow the timeline - adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + seekTrackToCurrent(); } else if (adjustableClock.IsRunning) { // If the user hasn't provided mouse input but the track is running, always follow the track - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + scrollToTrackTime(); } else { @@ -86,16 +86,19 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (adjustableClock.CurrentTime == lastTrackTime) { // The track hasn't been seeked externally - adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + seekTrackToCurrent(); } else { // The track has been seeked externally - ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + scrollToTrackTime(); } } lastTrackTime = adjustableClock.CurrentTime; + + void seekTrackToCurrent() => adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + void scrollToTrackTime() => ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) From d4f68e0b673c9e258180d5290e016a3fb0e7d105 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 24 May 2018 14:26:53 +0900 Subject: [PATCH 032/186] Fix possible NaN values due to trackvirtual infinite length --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index df615ad035..3fdde1fc1d 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Input; @@ -97,8 +98,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline lastTrackTime = adjustableClock.CurrentTime; - void seekTrackToCurrent() => adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); - void scrollToTrackTime() => ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + void seekTrackToCurrent() + { + if (!(Beatmap.Value.Track is TrackVirtual)) + adjustableClock.Seek(Current / Content.DrawWidth * Beatmap.Value.Track.Length); + } + + void scrollToTrackTime() + { + if (!(Beatmap.Value.Track is TrackVirtual)) + ScrollTo((float)(adjustableClock.CurrentTime / Beatmap.Value.Track.Length) * Content.DrawWidth, false); + } } protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) From b649025e861b14506754794e6416235b1e43d205 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 24 May 2018 14:36:48 +0900 Subject: [PATCH 033/186] beginUserDrag/endUserDrag --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 3fdde1fc1d..0ae6cd6da2 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -115,7 +115,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { if (base.OnMouseDown(state, args)) { - beginUserInput(); + beginUserDrag(); return true; } @@ -124,18 +124,18 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - endUserInput(); + endUserDrag(); return base.OnMouseUp(state, args); } - private void beginUserInput() + private void beginUserDrag() { handlingDragInput = true; trackWasPlaying = adjustableClock.IsRunning; adjustableClock.Stop(); } - private void endUserInput() + private void endUserDrag() { handlingDragInput = false; if (trackWasPlaying) @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline { if (base.OnMouseDown(state, args)) { - timeline.beginUserInput(); + timeline.beginUserDrag(); return true; } @@ -167,7 +167,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - timeline.endUserInput(); + timeline.endUserDrag(); return base.OnMouseUp(state, args); } } From 498244a3089827cbd58aff593d0ec3963cf32303 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 25 May 2018 00:37:53 +0300 Subject: [PATCH 034/186] Introduce PreviewTrack class --- osu.Game/Audio/PreviewTrack.cs | 39 +++++++++++++++++ osu.Game/Audio/PreviewTrackManager.cs | 43 ++++++++----------- .../BeatmapSet/Buttons/PreviewButton.cs | 6 +-- osu.Game/Overlays/Direct/DirectPanel.cs | 16 +++---- osu.Game/Overlays/Direct/PlayButton.cs | 18 ++++---- 5 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 osu.Game/Audio/PreviewTrack.cs diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs new file mode 100644 index 0000000000..10dec7c394 --- /dev/null +++ b/osu.Game/Audio/PreviewTrack.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio.Track; + +namespace osu.Game.Audio +{ + public class PreviewTrack + { + public readonly Track Track; + private readonly Action onStart; + private readonly Action onStop; + + public event Action Stopped; + public event Action Started; + + public PreviewTrack(Track track, Action onStart, Action onStop) + { + Track = track; + this.onStart = onStart; + this.onStop = onStop; + } + + public void Start() + { + onStart?.Invoke(this); + Track.Restart(); + Started?.Invoke(); + } + + public void Stop() + { + onStop?.Invoke(); + Track.Stop(); + Stopped?.Invoke(); + } + } +} diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 2e5f26bcf4..5c7f580ca8 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -14,13 +14,13 @@ namespace osu.Game.Audio { public class PreviewTrackManager : Component { - public event Action PlaybackStarted; - public event Action PlaybackStopped; + private Action onTrackStart; + private Action onTrackStop; private TrackManager trackManager; private BindableDouble muteBindable; - public Track CurrentTrack { get; private set; } + public PreviewTrack CurrentTrack { get; private set; } [BackgroundDependencyLoader] private void load(AudioManager audio, FrameworkConfigManager config) @@ -32,35 +32,28 @@ namespace osu.Game.Audio audio.AddItem(trackManager); config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); - PlaybackStarted += () => audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - PlaybackStopped += () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + onTrackStart = track => + { + CurrentTrack?.Stop(); + audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + CurrentTrack = track; + CurrentTrack.Stopped += () => CurrentTrack = null; + }; + onTrackStop = () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); } - public Track Get(BeatmapSetInfo beatmapSetInfo) => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"); + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) => + new PreviewTrack( + trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"), + onTrackStart, + onTrackStop); protected override void Update() { - if (CurrentTrack?.HasCompleted ?? false) - PlaybackStopped?.Invoke(); + if (CurrentTrack?.Track.HasCompleted ?? false) + CurrentTrack.Stop(); base.Update(); } - - public void Play(Track track) - { - Stop(); - CurrentTrack = track; - track.Restart(); - PlaybackStarted?.Invoke(); - } - - public void Stop() - { - if (CurrentTrack?.IsRunning ?? false) - { - CurrentTrack?.Stop(); - PlaybackStopped?.Invoke(); - } - } } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 08a99f1aea..78628675ac 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -2,13 +2,13 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private readonly Box bg, progress; private readonly PlayButton playButton; - private Track preview => playButton.Preview; + private PreviewTrack preview => playButton.Preview; public Bindable Playing => playButton.Playing; public BeatmapSetInfo BeatmapSet @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons if (Playing.Value && preview != null) { // prevent negative (potential infinite) width if a track without length was loaded - progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f; + progress.Width = preview.Track.Length > 0 ? (float)(preview.Track.CurrentTime / preview.Track.Length) : 0f; } else progress.Width = 0; diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index cc0123dabc..2ceefe31ef 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -4,22 +4,22 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using OpenTK.Graphics; -using osu.Framework.Input; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests; -using osu.Framework.Configuration; -using osu.Framework.Audio.Track; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays.Direct { @@ -37,7 +37,7 @@ namespace osu.Game.Overlays.Direct private BeatmapManager beatmaps; private BeatmapSetOverlay beatmapSetOverlay; - public Track Preview => PlayButton.Preview; + public PreviewTrack Preview => PlayButton.Preview; public Bindable PreviewPlaying => PlayButton.Playing; protected abstract PlayButton PlayButton { get; } protected abstract Box PreviewBar { get; } @@ -121,9 +121,9 @@ namespace osu.Game.Overlays.Direct { base.Update(); - if (PreviewPlaying && Preview != null && Preview.IsLoaded) + if (PreviewPlaying && Preview != null && Preview.Track.IsLoaded) { - PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length); + PreviewBar.Width = (float)(Preview.Track.CurrentTime / Preview.Track.Length); } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 77c904050b..1f18faaf14 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,7 +18,7 @@ namespace osu.Game.Overlays.Direct public class PlayButton : Container { public readonly Bindable Playing = new Bindable(); - public Track Preview { get; private set; } + public PreviewTrack Preview { get; private set; } private BeatmapSetInfo beatmapSet; @@ -32,6 +31,8 @@ namespace osu.Game.Overlays.Direct beatmapSet = value; Playing.Value = false; + if (Preview != null) + Preview.Stopped -= preview_Stopped; Preview = null; } } @@ -85,12 +86,6 @@ namespace osu.Game.Overlays.Direct { hoverColour = colour.Yellow; this.previewTrackManager = previewTrackManager; - - previewTrackManager.PlaybackStopped += () => - { - if (Preview == previewTrackManager.CurrentTrack) - Playing.Value = false; - }; } protected override bool OnClick(InputState state) @@ -134,21 +129,24 @@ namespace osu.Game.Overlays.Direct }) .ContinueWith(t => { + Preview.Stopped += preview_Stopped; playingStateChanged(true); loading = false; }); return; } - previewTrackManager.Play(Preview); + Preview.Start(); } else { - previewTrackManager.Stop(); + Preview.Stop(); loading = false; } } + private void preview_Stopped() => Playing.Value = false; + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); From a24589f5836d87b758ba3cafcc694676fb65d208 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 25 May 2018 22:35:15 +0300 Subject: [PATCH 035/186] Cleanup external PlayButton.Playing usage --- osu.Game/Audio/PreviewTrackManager.cs | 9 ++-- .../BeatmapSet/Buttons/PreviewButton.cs | 8 +-- osu.Game/Overlays/BeatmapSet/Details.cs | 6 ++- osu.Game/Overlays/Direct/DirectPanel.cs | 1 - osu.Game/Overlays/Direct/PlayButton.cs | 52 +++++++++---------- osu.Game/Overlays/DirectOverlay.cs | 26 ---------- 6 files changed, 37 insertions(+), 65 deletions(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 5c7f580ca8..5c2656b322 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -37,14 +37,17 @@ namespace osu.Game.Audio CurrentTrack?.Stop(); audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); CurrentTrack = track; - CurrentTrack.Stopped += () => CurrentTrack = null; }; - onTrackStop = () => audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + onTrackStop = () => + { + audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + CurrentTrack = null; + }; } public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) => new PreviewTrack( - trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineBeatmapSetID}.mp3"), + trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), onTrackStart, onTrackStop); diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 78628675ac..78bc77efe8 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons }, }; - Action = () => Playing.Value = !Playing.Value; + Action = () => playButton.TriggerOnClick(); Playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100); } @@ -89,12 +89,6 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons progress.Width = 0; } - protected override void Dispose(bool isDisposing) - { - Playing.Value = false; - base.Dispose(isDisposing); - } - protected override bool OnHover(InputState state) { bg.FadeColour(Color4.Black.Opacity(0.5f), 100); diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 5264caf936..8c16822cfc 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -102,7 +102,11 @@ namespace osu.Game.Overlays.BeatmapSet updateDisplay(); } - public void StopPreview() => preview.Playing.Value = false; + public void StopPreview() + { + if (preview.Playing) + preview.TriggerOnClick(); + } private class DetailBox : Container { diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 2ceefe31ef..1c7abd4cdd 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -149,7 +149,6 @@ namespace osu.Game.Overlays.Direct protected override bool OnClick(InputState state) { ShowInformation(); - PreviewPlaying.Value = false; return true; } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 1f18faaf14..677f74540b 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -31,8 +31,6 @@ namespace osu.Game.Overlays.Direct beatmapSet = value; Playing.Value = false; - if (Preview != null) - Preview.Stopped -= preview_Stopped; Preview = null; } } @@ -90,7 +88,30 @@ namespace osu.Game.Overlays.Direct protected override bool OnClick(InputState state) { - Playing.Value = !Playing.Value; + if (!Playing.Value) + { + if (Preview == null) + { + Task.Run(() => + { + loading = true; + return Preview = previewTrackManager.Get(beatmapSet); + }) + .ContinueWith(t => + { + Preview.Started += () => Playing.Value = true; + Preview.Stopped += () => Playing.Value = false; + Preview.Start(); + loading = false; + }); + return true; + } + + Preview.Start(); + } + else + Preview?.Stop(); + return true; } @@ -118,35 +139,12 @@ namespace osu.Game.Overlays.Direct icon.Icon = playing ? FontAwesome.fa_pause : FontAwesome.fa_play; icon.FadeColour(playing || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); - if (playing) + if (!playing) { - if (Preview == null) - { - Task.Run(() => - { - loading = true; - return Preview = previewTrackManager.Get(beatmapSet); - }) - .ContinueWith(t => - { - Preview.Stopped += preview_Stopped; - playingStateChanged(true); - loading = false; - }); - return; - } - - Preview.Start(); - } - else - { - Preview.Stop(); loading = false; } } - private void preview_Stopped() => Playing.Value = false; - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index f437546888..35a6e5fc48 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -33,7 +33,6 @@ namespace osu.Game.Overlays private readonly FillFlowContainer resultCountsContainer; private readonly OsuSpriteText resultCountsText; private FillFlowContainer panels; - private DirectPanel playing; protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74"); protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71"); @@ -217,12 +216,6 @@ namespace osu.Game.Overlays panels.FadeOut(200); panels.Expire(); panels = null; - - if (playing != null) - { - playing.PreviewPlaying.Value = false; - playing = null; - } } if (BeatmapSets == null) return; @@ -253,17 +246,6 @@ namespace osu.Game.Overlays { if (panels != null) ScrollFlow.Remove(panels); ScrollFlow.Add(panels = newPanels); - - foreach (DirectPanel panel in p.Children) - panel.PreviewPlaying.ValueChanged += newValue => - { - if (newValue) - { - if (playing != null && playing != panel) - playing.PreviewPlaying.Value = false; - playing = panel; - } - }; }); } @@ -313,14 +295,6 @@ namespace osu.Game.Overlays api.Queue(getSetsRequest); } - protected override void PopOut() - { - base.PopOut(); - - if (playing != null) - playing.PreviewPlaying.Value = false; - } - private int distinctCount(List list) => list.Distinct().ToArray().Length; protected override void Dispose(bool isDisposing) From 572c3f518948a1729a34e24646f252d7d65d6e1e Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 25 May 2018 23:51:05 +0300 Subject: [PATCH 036/186] Stop preview playback when an overlay is popping out --- osu.Game/Overlays/BeatmapSet/Details.cs | 6 ------ osu.Game/Overlays/BeatmapSetOverlay.cs | 15 +++++++++------ osu.Game/Overlays/DirectOverlay.cs | 13 +++++++++++-- osu.Game/Overlays/UserProfileOverlay.cs | 10 +++++++--- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 8c16822cfc..ccd0fa04ab 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -102,12 +102,6 @@ namespace osu.Game.Overlays.BeatmapSet updateDisplay(); } - public void StopPreview() - { - if (preview.Playing) - preview.TriggerOnClick(); - } - private class DetailBox : Container { private readonly Container content; diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 096f7bb63c..53bae54379 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -1,23 +1,24 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Allocation; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.BeatmapSet; -using osu.Game.Rulesets; using osu.Game.Overlays.BeatmapSet.Scores; -using System.Linq; +using osu.Game.Rulesets; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays { @@ -37,6 +38,7 @@ namespace osu.Game.Overlays private readonly ScrollContainer scroll; private BeatmapSetInfo beatmapSet; + private PreviewTrackManager previewTrackManager; public BeatmapSetInfo BeatmapSet { @@ -109,10 +111,11 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api, RulesetStore rulesets) + private void load(APIAccess api, RulesetStore rulesets, PreviewTrackManager previewTrackManager) { this.api = api; this.rulesets = rulesets; + this.previewTrackManager = previewTrackManager; } protected override void PopIn() @@ -124,7 +127,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - header.Details.StopPreview(); + previewTrackManager.CurrentTrack?.Stop(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 35a6e5fc48..c69dc57342 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -4,12 +4,12 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using OpenTK; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Threading; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -18,6 +18,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.Direct; using osu.Game.Overlays.SearchableList; using osu.Game.Rulesets; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Overlays @@ -176,11 +177,12 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps) + private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps, PreviewTrackManager previewTrackManager) { this.api = api; this.rulesets = rulesets; this.beatmaps = beatmaps; + this.previewTrackManager = previewTrackManager; resultCountsContainer.Colour = colours.Yellow; @@ -254,6 +256,7 @@ namespace osu.Game.Overlays private readonly Bindable currentQuery = new Bindable(); private ScheduledDelegate queryChangedDebounce; + private PreviewTrackManager previewTrackManager; private void updateSearch() { @@ -297,6 +300,12 @@ namespace osu.Game.Overlays private int distinctCount(List list) => list.Distinct().ToArray().Length; + protected override void PopOut() + { + previewTrackManager.CurrentTrack?.Stop(); + base.PopOut(); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index a4dd0c9ec3..04a93dea23 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -2,14 +2,13 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Linq; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -18,6 +17,8 @@ using osu.Game.Online.API.Requests; using osu.Game.Overlays.Profile; using osu.Game.Overlays.Profile.Sections; using osu.Game.Users; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Overlays { @@ -30,6 +31,7 @@ namespace osu.Game.Overlays protected ProfileHeader Header; private SectionsContainer sectionsContainer; private ProfileTabControl tabs; + private PreviewTrackManager previewTrackManager; public const float CONTENT_X_MARGIN = 50; @@ -56,9 +58,10 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(APIAccess api) + private void load(APIAccess api, PreviewTrackManager previewTrackManager) { this.api = api; + this.previewTrackManager = previewTrackManager; } protected override void PopIn() @@ -70,6 +73,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); + previewTrackManager.CurrentTrack?.Stop(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); } From ab3ac49a2d6ac9667709b61a694be91206ab9925 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 21:01:56 -0300 Subject: [PATCH 037/186] Add empty Match screen. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 23 ++++++++++++ .../Screens/Multi/Screens/Lounge/Lounge.cs | 2 +- osu.Game/Screens/Multi/Screens/Match.cs | 37 ------------------- osu.Game/Screens/Multi/Screens/Match/Match.cs | 19 ++++++++++ osu.Game/Screens/Multi/Screens/MatchCreate.cs | 20 ---------- 5 files changed, 43 insertions(+), 58 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseMatch.cs delete mode 100644 osu.Game/Screens/Multi/Screens/Match.cs create mode 100644 osu.Game/Screens/Multi/Screens/Match/Match.cs delete mode 100644 osu.Game/Screens/Multi/Screens/MatchCreate.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs new file mode 100644 index 0000000000..9e62a19897 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Multi.Screens.Match; + +namespace osu.Game.Tests.Visual +{ + public class TestCaseMatch : OsuTestCase + { + public TestCaseMatch() + { + Room room = new Room + { + }; + + Match match = new Match(room); + + AddStep(@"show", () => Add(match)); + AddStep(@"exit", match.Exit); + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs index 60ffe2c0b9..c83ecee1f0 100644 --- a/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs +++ b/osu.Game/Screens/Multi/Screens/Lounge/Lounge.cs @@ -164,7 +164,7 @@ namespace osu.Game.Screens.Multi.Screens.Lounge // open the room if its selected and is clicked again if (room.State == SelectionState.Selected) - Push(new Match()); + Push(new Match.Match(room.Room)); } private class RoomsFilterContainer : FillFlowContainer, IHasFilterableChildren diff --git a/osu.Game/Screens/Multi/Screens/Match.cs b/osu.Game/Screens/Multi/Screens/Match.cs deleted file mode 100644 index 4ba7fe9f6a..0000000000 --- a/osu.Game/Screens/Multi/Screens/Match.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using osu.Framework.Graphics; -using osu.Framework.Screens; -using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Play; -using osu.Game.Screens.Select; -using OpenTK.Graphics; - -namespace osu.Game.Screens.Multi.Screens -{ - public class Match : ScreenWhiteBox - { - protected override IEnumerable PossibleChildren => new[] { - typeof(MatchSongSelect), - typeof(Player), - }; - - protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4"); - - protected override void OnEntering(Screen last) - { - base.OnEntering(last); - - Background.FadeColour(Color4.DarkGray, 500); - } - - protected override bool OnExiting(Screen next) - { - Background.FadeColour(Color4.White, 500); - return base.OnExiting(next); - } - } -} diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs new file mode 100644 index 0000000000..f70ed9eaa4 --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Online.Multiplayer; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Match : MultiplayerScreen + { + private readonly Room room; + + public override string Title => room.Name.Value; + + public Match(Room room) + { + this.room = room; + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/MatchCreate.cs b/osu.Game/Screens/Multi/Screens/MatchCreate.cs deleted file mode 100644 index 6b4e26d5e5..0000000000 --- a/osu.Game/Screens/Multi/Screens/MatchCreate.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; - -namespace osu.Game.Screens.Multi.Screens -{ - public class MatchCreate : ScreenWhiteBox - { - protected override IEnumerable PossibleChildren => new[] { - typeof(Match) - }; - - public MatchCreate() - { - ValidForResume = false; - } - } -} From 98819880c4a3018e2d840be335ce2a542629611d Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Mon, 28 May 2018 22:11:01 -0300 Subject: [PATCH 038/186] Add match screen header. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 17 ++ .../Screens/Multi/Screens/Match/Header.cs | 169 ++++++++++++++++++ osu.Game/Screens/Multi/Screens/Match/Match.cs | 23 +++ 3 files changed, 209 insertions(+) create mode 100644 osu.Game/Screens/Multi/Screens/Match/Header.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 9e62a19897..5dc330704d 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Screens.Match; @@ -12,6 +13,22 @@ namespace osu.Game.Tests.Visual { Room room = new Room { + Beatmap = + { + Value = new BeatmapInfo + { + BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/765055/covers/cover.jpg?1526955337", + }, + }, + }, + }, + }, }; Match match = new Match(room); diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs new file mode 100644 index 0000000000..b1f9e0dfc6 --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -0,0 +1,169 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.SearchableList; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Header : Container + { + private readonly Box tabStrip; + private readonly UpdateableBeatmapSetCover cover; + + public readonly OsuClickableContainer BeatmapButton; + + public BeatmapSetInfo BeatmapSet + { + set { cover.BeatmapSet = value; } + } + + public Header() + { + RelativeSizeAxes = Axes.X; + Height = 200; + + Children = new Drawable[] + { + cover = new UpdateableBeatmapSetCover + { + RelativeSizeAxes = Axes.Both, + Masking = true, + }, + tabStrip = new Box + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = 1, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 200, + Padding = new MarginPadding { Vertical = 5 }, + Child = BeatmapButton = new BeatmapSelectButton + { + RelativeSizeAxes = Axes.Both, + }, + }, + new PageTabControl + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + }, + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + tabStrip.Colour = colours.Yellow; + } + + private class BeatmapSelectButton : OsuClickableContainer + { + private const float corner_radius = 5; + private const float bg_opacity = 0.5f; + private const float transition_duration = 100; + + private readonly Box bg; + private readonly Container border; + + public BeatmapSelectButton() + { + Masking = true; + CornerRadius = corner_radius; + + Children = new Drawable[] + { + bg = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = bg_opacity, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = @"Exo2.0-Bold", + Text = "Select Beatmap", + }, + border = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = corner_radius, + BorderThickness = 4, + Alpha = 0f, + Child = new Box // needs a child to show the border + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0), + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + border.BorderColour = colours.Yellow; + } + + protected override bool OnHover(InputState state) + { + border.FadeIn(transition_duration); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + base.OnHoverLost(state); + border.FadeOut(transition_duration); + } + + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) + { + bg.FadeTo(0.75f, 1000, Easing.Out); + return base.OnMouseDown(state, args); + } + + protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) + { + bg.FadeTo(bg_opacity, transition_duration); + return base.OnMouseUp(state, args); + } + } + } + + public enum MatchHeaderPage + { + Settings, + Room, + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index f70ed9eaa4..82f5b53ee2 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -1,19 +1,42 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; +using osu.Game.Screens.Select; namespace osu.Game.Screens.Multi.Screens.Match { public class Match : MultiplayerScreen { private readonly Room room; + private readonly Bindable beatmapBind = new Bindable(); public override string Title => room.Name.Value; public Match(Room room) { this.room = room; + Header header; + + Children = new Drawable[] + { + header = new Header(), + }; + + header.BeatmapButton.Action = () => + { + Push(new MatchSongSelect()); + }; + + beatmapBind.ValueChanged += b => + { + header.BeatmapSet = b.BeatmapSet; + }; + + beatmapBind.BindTo(room.Beatmap); } } } From c8ce34b6d4a80f8c8a2414a3296e21642003f24d Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 01:51:04 -0300 Subject: [PATCH 039/186] Add Match Info. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 17 +- .../Screens/Multi/Screens/Match/Header.cs | 5 +- osu.Game/Screens/Multi/Screens/Match/Info.cs | 194 ++++++++++++++++++ osu.Game/Screens/Multi/Screens/Match/Match.cs | 24 ++- 4 files changed, 234 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Screens/Multi/Screens/Match/Info.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 5dc330704d..9c385feacb 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -1,22 +1,37 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; using osu.Game.Screens.Multi.Screens.Match; namespace osu.Game.Tests.Visual { public class TestCaseMatch : OsuTestCase { - public TestCaseMatch() + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) { Room room = new Room { + Name = { Value = @"One Awesome Room" }, + Status = { Value = new RoomStatusOpen() }, + Availability = { Value = RoomAvailability.Public }, + Type = { Value = new GameTypeTeamVersus() }, Beatmap = { Value = new BeatmapInfo { + StarDifficulty = 5.02, + Ruleset = rulesets.GetRuleset(1), + Metadata = new BeatmapMetadata + { + Title = @"Paradigm Shift", + Artist = @"Morimori Atsushi", + AuthorString = @"eiri-", + }, BeatmapSet = new BeatmapSetInfo { OnlineInfo = new BeatmapSetOnlineInfo diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index b1f9e0dfc6..fde6859d95 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -20,6 +20,8 @@ namespace osu.Game.Screens.Multi.Screens.Match { public class Header : Container { + public const float HEIGHT = 200; + private readonly Box tabStrip; private readonly UpdateableBeatmapSetCover cover; @@ -33,10 +35,11 @@ namespace osu.Game.Screens.Multi.Screens.Match public Header() { RelativeSizeAxes = Axes.X; - Height = 200; + Height = HEIGHT; Children = new Drawable[] { + // todo: gradient over the cover cover = new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs new file mode 100644 index 0000000000..634b91cf7a --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -0,0 +1,194 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Multiplayer; +using osu.Game.Overlays.SearchableList; +using osu.Game.Screens.Multi.Components; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Info : Container + { + public const float HEIGHT = 128; + + private readonly OsuSpriteText name, availabilityStatus; + private readonly BeatmapTypeInfo beatmapTypeInfo; + + private OsuColour colours; + + public string Name + { + set { name.Text = value; } + } + + private RoomAvailability availability; + public RoomAvailability Availability + { + set + { + if (value == availability) return; + availability = value; + + if (IsLoaded) + updateAvailabilityStatus(); + } + } + + private RoomStatus status; + public RoomStatus Status + { + set + { + if (value == status) return; + status = value; + + if (IsLoaded) + updateAvailabilityStatus(); + } + } + + public BeatmapInfo Beatmap + { + set { beatmapTypeInfo.Beatmap = value; } + } + + public GameType Type + { + set { beatmapTypeInfo.Type = value; } + } + + public Info() + { + RelativeSizeAxes = Axes.X; + Height = HEIGHT; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.FromHex(@"28242d"), + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Padding = new MarginPadding { Vertical = 20 }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + name = new OsuSpriteText + { + TextSize = 30, + }, + availabilityStatus = new OsuSpriteText + { + TextSize = 14, + }, + }, + }, + beatmapTypeInfo = new BeatmapTypeInfo + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + }, + }, + }, + new ReadyButton + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 200, + Padding = new MarginPadding { Vertical = 10 }, + }, + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + this.colours = colours; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateAvailabilityStatus(); + } + + private void updateAvailabilityStatus() + { + if (status != null) + { + availabilityStatus.FadeColour(status.GetAppropriateColour(colours)); + availabilityStatus.Text = $"{availability.GetDescription()}, {status.Message}"; + } + } + + private class ReadyButton : TriangleButton + { + public readonly Bindable Ready = new Bindable(); + + protected override SpriteText CreateText() => new OsuSpriteText + { + Depth = -1, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Font = @"Exo2.0-Light", + TextSize = 30, + }; + + public ReadyButton() + { + Height = 1; + Text = "Ready"; + + Action = () => Ready.Value = !Ready.Value; + } + + [BackgroundDependencyLoader] + private void load() + { + BackgroundColour = OsuColour.FromHex(@"1187aa"); + Triangles.ColourLight = OsuColour.FromHex(@"277b9c"); + Triangles.ColourDark = OsuColour.FromHex(@"1f6682"); + Triangles.TriangleScale = 1.5f; + + // todo: visually select + Ready.ValueChanged += value => + { + if (value) + Text = "Not Ready"; + else + Text = "Ready"; + }; + } + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 82f5b53ee2..e83769daa0 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -12,6 +12,11 @@ namespace osu.Game.Screens.Multi.Screens.Match public class Match : MultiplayerScreen { private readonly Room room; + + private readonly Bindable nameBind = new Bindable(); + private readonly Bindable statusBind = new Bindable(); + private readonly Bindable availabilityBind = new Bindable(); + private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); public override string Title => room.Name.Value; @@ -20,22 +25,33 @@ namespace osu.Game.Screens.Multi.Screens.Match { this.room = room; Header header; + Info info; Children = new Drawable[] { header = new Header(), + info = new Info + { + Margin = new MarginPadding { Top = Header.HEIGHT }, + }, }; - header.BeatmapButton.Action = () => - { - Push(new MatchSongSelect()); - }; + header.BeatmapButton.Action = () => Push(new MatchSongSelect()); + nameBind.ValueChanged += n => info.Name = n; + statusBind.ValueChanged += s => info.Status = s; + availabilityBind.ValueChanged += a => info.Availability = a; + typeBind.ValueChanged += t => info.Type = t; beatmapBind.ValueChanged += b => { header.BeatmapSet = b.BeatmapSet; + info.Beatmap = b; }; + nameBind.BindTo(room.Name); + statusBind.BindTo(room.Status); + availabilityBind.BindTo(room.Availability); + typeBind.BindTo(room.Type); beatmapBind.BindTo(room.Beatmap); } } From 77ff0640c24a5005486337b8ac3cd95369b6a3c2 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 01:53:45 -0300 Subject: [PATCH 040/186] Add a gradient over the cover in Header. --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index fde6859d95..1d414e338c 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input; @@ -39,12 +40,16 @@ namespace osu.Game.Screens.Multi.Screens.Match Children = new Drawable[] { - // todo: gradient over the cover cover = new UpdateableBeatmapSetCover { RelativeSizeAxes = Axes.Both, Masking = true, }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Black.Opacity(0.5f)), + }, tabStrip = new Box { Anchor = Anchor.BottomLeft, From 3915cb7f2f7cde41e6688905cd9bfed2c8487008 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 02:42:52 -0300 Subject: [PATCH 041/186] Add Match Participants, change Room.Users to IEnumerable. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 38 ++++++++++ osu.Game/Online/Multiplayer/Room.cs | 3 +- .../Screens/Multi/Components/DrawableRoom.cs | 2 +- .../Screens/Multi/Components/RoomInspector.cs | 5 +- osu.Game/Screens/Multi/Screens/Match/Match.cs | 17 +++++ .../Multi/Screens/Match/Participants.cs | 71 +++++++++++++++++++ .../Multi/Screens/MultiplayerScreen.cs | 1 + 7 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/Multi/Screens/Match/Participants.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 9c385feacb..6f41723982 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -6,6 +6,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Screens.Multi.Screens.Match; +using osu.Game.Users; namespace osu.Game.Tests.Visual { @@ -44,6 +45,43 @@ namespace osu.Game.Tests.Visual }, }, }, + MaxParticipants = { Value = 5 }, + Participants = + { + Value = new[] + { + new User + { + Username = @"eiri-", + Id = 3388410, + Country = new Country { FlagName = @"US" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/3388410/00a8486a247831e1cc4375db519f611ac970bda8bc0057d78b0f540ea38c3e58.jpeg", + IsSupporter = true, + }, + new User + { + Username = @"Nepuri", + Id = 6637817, + Country = new Country { FlagName = @"DE" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/6637817/9085fc60248b6b5327a72c1dcdecf2dbedba810ae0ab6bcf7224e46b1339632a.jpeg", + IsSupporter = true, + }, + new User + { + Username = @"goheegy", + Id = 8057655, + Country = new Country { FlagName = @"GB" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/8057655/21cec27c25a11dc197a4ec6a74253dbabb495949b0e0697113352f12007018c5.jpeg", + }, + new User + { + Username = @"Alumetri", + Id = 5371497, + Country = new Country { FlagName = @"RU" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5371497/e023b8c7fbe3613e64bd4856703517ea50fbed8a5805dc9acda9efe9897c67e2.jpeg", + }, + } + }, }; Match match = new Match(room); diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs index ae3fb5ec6e..b076afbcdb 100644 --- a/osu.Game/Online/Multiplayer/Room.cs +++ b/osu.Game/Online/Multiplayer/Room.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Framework.Configuration; using osu.Game.Beatmaps; using osu.Game.Users; @@ -16,6 +17,6 @@ namespace osu.Game.Online.Multiplayer public Bindable Type = new Bindable(); public Bindable Beatmap = new Bindable(); public Bindable MaxParticipants = new Bindable(); - public Bindable Participants = new Bindable(); + public Bindable> Participants = new Bindable>(); } } diff --git a/osu.Game/Screens/Multi/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Components/DrawableRoom.cs index d31019a259..54bd0ae7cc 100644 --- a/osu.Game/Screens/Multi/Components/DrawableRoom.cs +++ b/osu.Game/Screens/Multi/Components/DrawableRoom.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Multi.Components private readonly Bindable statusBind = new Bindable(); private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); - private readonly Bindable participantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); public readonly Room Room; diff --git a/osu.Game/Screens/Multi/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Components/RoomInspector.cs index 14f4feab05..22bca1efc7 100644 --- a/osu.Game/Screens/Multi/Components/RoomInspector.cs +++ b/osu.Game/Screens/Multi/Components/RoomInspector.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; @@ -33,7 +34,7 @@ namespace osu.Game.Screens.Multi.Components private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); private readonly Bindable maxParticipantsBind = new Bindable(); - private readonly Bindable participantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); private OsuColour colours; private Box statusStrip; @@ -214,7 +215,7 @@ namespace osu.Game.Screens.Multi.Components participantsBind.ValueChanged += p => { - participantCount.Count = p.Length; + participantCount.Count = p.Count(); participantInfo.Participants = p; participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)); }; diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index e83769daa0..3a2aef2ff4 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -1,23 +1,31 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Screens.Select; +using osu.Game.Users; namespace osu.Game.Screens.Multi.Screens.Match { public class Match : MultiplayerScreen { private readonly Room room; + private readonly Participants participants; private readonly Bindable nameBind = new Bindable(); private readonly Bindable statusBind = new Bindable(); private readonly Bindable availabilityBind = new Bindable(); private readonly Bindable typeBind = new Bindable(); private readonly Bindable beatmapBind = new Bindable(); + private readonly Bindable maxParticipantsBind = new Bindable(); + private readonly Bindable> participantsBind = new Bindable>(); + + protected override Container TransitionContent => participants; public override string Title => room.Name.Value; @@ -34,6 +42,11 @@ namespace osu.Game.Screens.Multi.Screens.Match { Margin = new MarginPadding { Top = Header.HEIGHT }, }, + participants = new Participants + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = Header.HEIGHT + Info.HEIGHT }, + }, }; header.BeatmapButton.Action = () => Push(new MatchSongSelect()); @@ -41,6 +54,8 @@ namespace osu.Game.Screens.Multi.Screens.Match statusBind.ValueChanged += s => info.Status = s; availabilityBind.ValueChanged += a => info.Availability = a; typeBind.ValueChanged += t => info.Type = t; + maxParticipantsBind.ValueChanged += m => { participants.Max = m; }; + participantsBind.ValueChanged += p => participants.Users = p; beatmapBind.ValueChanged += b => { @@ -53,6 +68,8 @@ namespace osu.Game.Screens.Multi.Screens.Match availabilityBind.BindTo(room.Availability); typeBind.BindTo(room.Type); beatmapBind.BindTo(room.Beatmap); + maxParticipantsBind.BindTo(room.MaxParticipants); + participantsBind.BindTo(room.Participants); } } } diff --git a/osu.Game/Screens/Multi/Screens/Match/Participants.cs b/osu.Game/Screens/Multi/Screens/Match/Participants.cs new file mode 100644 index 0000000000..11e27c0a18 --- /dev/null +++ b/osu.Game/Screens/Multi/Screens/Match/Participants.cs @@ -0,0 +1,71 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays.SearchableList; +using osu.Game.Screens.Multi.Components; +using osu.Game.Users; +using OpenTK; + +namespace osu.Game.Screens.Multi.Screens.Match +{ + public class Participants : Container + { + private readonly ParticipantCount count; + private readonly FillFlowContainer usersFlow; + + public IEnumerable Users + { + set { + usersFlow.Children = value.Select(u => new UserPanel(u) + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 300, + }).ToList(); + + count.Count = value.Count(); + } + } + + public int? Max + { + set { count.Max = value; } + } + + public Participants() + { + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING }, + Children = new Drawable[] + { + new ScrollContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 10 }, + Children = new Drawable[] + { + count = new ParticipantCount + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }, + usersFlow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(5), + Padding = new MarginPadding { Top = 40 }, + }, + }, + }, + }, + }; + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs index 191fe66037..9daa4e732b 100644 --- a/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs +++ b/osu.Game/Screens/Multi/Screens/MultiplayerScreen.cs @@ -21,6 +21,7 @@ namespace osu.Game.Screens.Multi.Screens TransitionContent.MoveToX(200); + Content.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing); TransitionContent.FadeInFromZero(WaveContainer.APPEAR_DURATION, in_easing); TransitionContent.MoveToX(0, WaveContainer.APPEAR_DURATION, in_easing); } From 94b54a0520d4f2d091d531786c63b527a8db2629 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:03:51 -0300 Subject: [PATCH 042/186] Adjust design of ReadyButton. --- osu.Game/Screens/Multi/Screens/Match/Info.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs index 634b91cf7a..88dda4a67b 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Info.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -180,13 +180,31 @@ namespace osu.Game.Screens.Multi.Screens.Match Triangles.ColourDark = OsuColour.FromHex(@"1f6682"); Triangles.TriangleScale = 1.5f; - // todo: visually select + Container active; + Add(active = new Container + { + RelativeSizeAxes = Axes.Both, + Alpha = 0f, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.15f, + Blending = BlendingMode.Additive, + }, + }); + Ready.ValueChanged += value => { if (value) + { Text = "Not Ready"; + active.FadeIn(200); + } else + { Text = "Ready"; + active.FadeOut(200); + } }; } } From b4b4a8a157a0bbcb5e99269ff3772afeff7f2545 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:24:38 -0300 Subject: [PATCH 043/186] Add TestCaseMatchInfo. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 2 + osu.Game.Tests/Visual/TestCaseMatchInfo.cs | 59 ++++++++++++++++++++ osu.Game/Screens/Multi/Screens/Match/Info.cs | 7 ++- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchInfo.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 6f41723982..69c1a6a0b2 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; @@ -10,6 +11,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual { + [TestFixture] public class TestCaseMatch : OsuTestCase { [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs new file mode 100644 index 0000000000..f58bc0e30a --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; +using osu.Game.Rulesets; +using osu.Game.Screens.Multi.Screens.Match; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseMatchInfo : OsuTestCase + { + [BackgroundDependencyLoader] + private void load(RulesetStore rulesets) + { + Info info = new Info(); + Add(info); + + AddStep(@"set name", () => info.Name = @"Room Name?"); + AddStep(@"set availability", () => info.Availability = RoomAvailability.FriendsOnly); + AddStep(@"set status", () => info.Status = new RoomStatusPlaying()); + + AddStep(@"set beatmap", () => info.Beatmap = new BeatmapInfo + { + StarDifficulty = 2.4, + Ruleset = rulesets.GetRuleset(0), + Metadata = new BeatmapMetadata + { + Title = @"My Song", + Artist = @"VisualTests", + AuthorString = @"osu!lazer", + }, + }); + + AddStep(@"set type", () => info.Type = new GameTypeTagTeam()); + + AddStep(@"change name", () => info.Name = @"Room Name!"); + AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly); + AddStep(@"change status", () => info.Status = new RoomStatusOpen()); + + AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo + { + StarDifficulty = 4.2, + Ruleset = rulesets.GetRuleset(3), + Metadata = new BeatmapMetadata + { + Title = @"Your Song", + Artist = @"Tester", + AuthorString = @"Someone", + }, + }); + + AddStep(@"change type", () => info.Type = new GameTypeTeamVersus()); + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Info.cs b/osu.Game/Screens/Multi/Screens/Match/Info.cs index 88dda4a67b..e2efbad269 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Info.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Info.cs @@ -24,9 +24,12 @@ namespace osu.Game.Screens.Multi.Screens.Match private readonly OsuSpriteText name, availabilityStatus; private readonly BeatmapTypeInfo beatmapTypeInfo; + private readonly ReadyButton readyButton; private OsuColour colours; + public Bindable Ready => readyButton.Ready; + public string Name { set { name.Text = value; } @@ -116,7 +119,7 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }, }, - new ReadyButton + readyButton = new ReadyButton { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -146,7 +149,7 @@ namespace osu.Game.Screens.Multi.Screens.Match { if (status != null) { - availabilityStatus.FadeColour(status.GetAppropriateColour(colours)); + availabilityStatus.FadeColour(status.GetAppropriateColour(colours), 100); availabilityStatus.Text = $"{availability.GetDescription()}, {status.Message}"; } } From 8595c821b438cf2d5c8a2d7bb3d06b8d46f9a1ec Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:34:02 -0300 Subject: [PATCH 044/186] Add TestCaseMatchHeader. --- osu.Game.Tests/Visual/TestCaseMatchHeader.cs | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchHeader.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatchHeader.cs b/osu.Game.Tests/Visual/TestCaseMatchHeader.cs new file mode 100644 index 0000000000..34f98f97c2 --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchHeader.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Screens.Multi.Screens.Match; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseMatchHeader : OsuTestCase + { + public TestCaseMatchHeader() + { + Header header = new Header(); + Add(header); + + AddStep(@"set beatmap set", () => header.BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/760757/covers/cover.jpg?1526944540", + }, + }, + }); + + AddStep(@"change beatmap set", () => header.BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/761883/covers/cover.jpg?1525557400", + }, + }, + }); + + AddStep(@"null beatmap set", () => header.BeatmapSet = null); + } + } +} From 7edb82eb85db1bca1bbccaabca2a625242d16f3a Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 03:53:30 -0300 Subject: [PATCH 045/186] Add TestCaseMatchParticipants. --- osu.Game.Tests/Visual/TestCaseMatchInfo.cs | 2 - .../Visual/TestCaseMatchParticipants.cs | 56 +++++++++++++++++++ .../Multi/Screens/Match/Participants.cs | 3 + 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/TestCaseMatchParticipants.cs diff --git a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs index f58bc0e30a..da5f429363 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs +++ b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs @@ -22,7 +22,6 @@ namespace osu.Game.Tests.Visual AddStep(@"set name", () => info.Name = @"Room Name?"); AddStep(@"set availability", () => info.Availability = RoomAvailability.FriendsOnly); AddStep(@"set status", () => info.Status = new RoomStatusPlaying()); - AddStep(@"set beatmap", () => info.Beatmap = new BeatmapInfo { StarDifficulty = 2.4, @@ -40,7 +39,6 @@ namespace osu.Game.Tests.Visual AddStep(@"change name", () => info.Name = @"Room Name!"); AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly); AddStep(@"change status", () => info.Status = new RoomStatusOpen()); - AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo { StarDifficulty = 4.2, diff --git a/osu.Game.Tests/Visual/TestCaseMatchParticipants.cs b/osu.Game.Tests/Visual/TestCaseMatchParticipants.cs new file mode 100644 index 0000000000..d6ae07252b --- /dev/null +++ b/osu.Game.Tests/Visual/TestCaseMatchParticipants.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Screens.Multi.Screens.Match; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual +{ + [TestFixture] + public class TestCaseMatchParticipants : OsuTestCase + { + public TestCaseMatchParticipants() + { + Participants participants; + Add(participants = new Participants + { + RelativeSizeAxes = Axes.Both, + }); + + AddStep(@"set max to null", () => participants.Max = null); + AddStep(@"set users", () => participants.Users = new[] + { + new User + { + Username = @"Feppla", + Id = 4271601, + Country = new Country { FlagName = @"SE" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg", + IsSupporter = true, + }, + new User + { + Username = @"Xilver", + Id = 3099689, + Country = new Country { FlagName = @"IL" }, + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg", + IsSupporter = true, + }, + new User + { + Username = @"Wucki", + Id = 5287410, + Country = new Country { FlagName = @"FI" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg", + IsSupporter = true, + }, + }); + + AddStep(@"set max", () => participants.Max = 10); + AddStep(@"clear users", () => participants.Users = new User[] { }); + AddStep(@"set max to null", () => participants.Max = null); + } + } +} diff --git a/osu.Game/Screens/Multi/Screens/Match/Participants.cs b/osu.Game/Screens/Multi/Screens/Match/Participants.cs index 11e27c0a18..182aa1e04e 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Participants.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Participants.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Multi.Screens.Match Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Width = 300, + OnLoadComplete = d => d.FadeInFromZero(60), }).ToList(); count.Count = value.Count(); @@ -61,6 +62,8 @@ namespace osu.Game.Screens.Multi.Screens.Match AutoSizeAxes = Axes.Y, Spacing = new Vector2(5), Padding = new MarginPadding { Top = 40 }, + LayoutDuration = 200, + LayoutEasing = Easing.OutQuint, }, }, }, From 9a7e5a3e2c26a8113a3b3182e750ca76d1306a17 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Tue, 29 May 2018 04:16:19 -0300 Subject: [PATCH 046/186] Update TestCaseMatch. --- osu.Game.Tests/Visual/TestCaseMatch.cs | 47 +++++++++++++++++++ osu.Game.Tests/Visual/TestCaseMatchInfo.cs | 4 +- osu.Game/Screens/Multi/Screens/Match/Match.cs | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseMatch.cs b/osu.Game.Tests/Visual/TestCaseMatch.cs index 69c1a6a0b2..bb22358425 100644 --- a/osu.Game.Tests/Visual/TestCaseMatch.cs +++ b/osu.Game.Tests/Visual/TestCaseMatch.cs @@ -89,6 +89,53 @@ namespace osu.Game.Tests.Visual Match match = new Match(room); AddStep(@"show", () => Add(match)); + AddStep(@"null beatmap", () => room.Beatmap.Value = null); + AddStep(@"change name", () => room.Name.Value = @"Two Awesome Rooms"); + AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying()); + AddStep(@"change availability", () => room.Availability.Value = RoomAvailability.FriendsOnly); + AddStep(@"change type", () => room.Type.Value = new GameTypeTag()); + AddStep(@"change beatmap", () => room.Beatmap.Value = new BeatmapInfo + { + StarDifficulty = 4.33, + Ruleset = rulesets.GetRuleset(2), + Metadata = new BeatmapMetadata + { + Title = @"Yasashisa no Riyuu", + Artist = @"ChouCho", + AuthorString = @"celerih", + }, + BeatmapSet = new BeatmapSetInfo + { + OnlineInfo = new BeatmapSetOnlineInfo + { + Covers = new BeatmapSetOnlineCovers + { + Cover = @"https://assets.ppy.sh/beatmaps/685391/covers/cover.jpg?1524597970", + }, + }, + }, + }); + + AddStep(@"null max participants", () => room.MaxParticipants.Value = null); + AddStep(@"change participants", () => room.Participants.Value = new[] + { + new User + { + Username = @"Spectator", + Id = 702598, + Country = new Country { FlagName = @"KR" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/702598/3bbf4cb8b8d2cf8b03145000a975ff27e191ab99b0920832e7dd67386280e288.jpeg", + IsSupporter = true, + }, + new User + { + Username = @"celerih", + Id = 4696296, + Country = new Country { FlagName = @"CA" }, + CoverUrl = @"https://assets.ppy.sh/user-profile-covers/4696296/7f8500731d0ac66d5472569d146a7be07d9460273361913f22c038867baddaef.jpeg", + }, + }); + AddStep(@"exit", match.Exit); } } diff --git a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs index da5f429363..205da6932f 100644 --- a/osu.Game.Tests/Visual/TestCaseMatchInfo.cs +++ b/osu.Game.Tests/Visual/TestCaseMatchInfo.cs @@ -39,6 +39,8 @@ namespace osu.Game.Tests.Visual AddStep(@"change name", () => info.Name = @"Room Name!"); AddStep(@"change availability", () => info.Availability = RoomAvailability.InviteOnly); AddStep(@"change status", () => info.Status = new RoomStatusOpen()); + AddStep(@"null beatmap", () => info.Beatmap = null); + AddStep(@"change type", () => info.Type = new GameTypeTeamVersus()); AddStep(@"change beatmap", () => info.Beatmap = new BeatmapInfo { StarDifficulty = 4.2, @@ -50,8 +52,6 @@ namespace osu.Game.Tests.Visual AuthorString = @"Someone", }, }); - - AddStep(@"change type", () => info.Type = new GameTypeTeamVersus()); } } } diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 3a2aef2ff4..525682e9c5 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Multi.Screens.Match beatmapBind.ValueChanged += b => { - header.BeatmapSet = b.BeatmapSet; + header.BeatmapSet = b?.BeatmapSet; info.Beatmap = b; }; From 88ac427ba67a216dff3dc654279fa95cac013df4 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 1 Jun 2018 21:06:37 +0300 Subject: [PATCH 047/186] PreviewTrack.Owner --- osu.Game/Audio/PreviewTrack.cs | 6 +++++- osu.Game/Audio/PreviewTrackManager.cs | 6 ++++-- osu.Game/Overlays/BeatmapSetOverlay.cs | 3 ++- osu.Game/Overlays/Direct/PlayButton.cs | 14 +++++++++++++- osu.Game/Overlays/DirectOverlay.cs | 3 ++- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 10dec7c394..d182df42e4 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -3,23 +3,27 @@ using System; using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Containers; namespace osu.Game.Audio { public class PreviewTrack { public readonly Track Track; + public readonly OverlayContainer Owner; + private readonly Action onStart; private readonly Action onStop; public event Action Stopped; public event Action Started; - public PreviewTrack(Track track, Action onStart, Action onStop) + public PreviewTrack(Track track, Action onStart, Action onStop, OverlayContainer owner) { Track = track; this.onStart = onStart; this.onStop = onStop; + Owner = owner; } public void Start() diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 5c2656b322..59a088d954 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -7,6 +7,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.IO.Stores; using osu.Game.Beatmaps; @@ -45,11 +46,12 @@ namespace osu.Game.Audio }; } - public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo) => + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) => new PreviewTrack( trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), onTrackStart, - onTrackStop); + onTrackStop, + previewOwner); protected override void Update() { diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 53bae54379..cccd51a621 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -127,7 +127,8 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - previewTrackManager.CurrentTrack?.Stop(); + if (previewTrackManager.CurrentTrack?.Owner == this) + previewTrackManager.CurrentTrack?.Stop(); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 677f74540b..a5c9da4fba 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -35,6 +35,18 @@ namespace osu.Game.Overlays.Direct } } + private OverlayContainer parentOverlayContainer + { + get + { + var d = Parent; + while (!(d is OverlayContainer)) + d = d.Parent; + + return (OverlayContainer)d; + } + } + private PreviewTrackManager previewTrackManager; private Color4 hoverColour; @@ -95,7 +107,7 @@ namespace osu.Game.Overlays.Direct Task.Run(() => { loading = true; - return Preview = previewTrackManager.Get(beatmapSet); + return Preview = previewTrackManager.Get(beatmapSet, parentOverlayContainer); }) .ContinueWith(t => { diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index c69dc57342..72de8ebc84 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -302,7 +302,8 @@ namespace osu.Game.Overlays protected override void PopOut() { - previewTrackManager.CurrentTrack?.Stop(); + if (previewTrackManager.CurrentTrack?.Owner == this) + previewTrackManager.CurrentTrack?.Stop(); base.PopOut(); } From 556673266427af65322f62e4893dd224df330165 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 1 Jun 2018 21:36:30 +0300 Subject: [PATCH 048/186] Get rid of PreviewTrackManager.onTrackStart and PreviewTrackManager.onTrackStop delegates --- osu.Game/Audio/PreviewTrack.cs | 9 +----- osu.Game/Audio/PreviewTrackManager.cs | 43 ++++++++++++++------------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index d182df42e4..1250d4864e 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -12,30 +12,23 @@ namespace osu.Game.Audio public readonly Track Track; public readonly OverlayContainer Owner; - private readonly Action onStart; - private readonly Action onStop; - public event Action Stopped; public event Action Started; - public PreviewTrack(Track track, Action onStart, Action onStop, OverlayContainer owner) + public PreviewTrack(Track track, OverlayContainer owner) { Track = track; - this.onStart = onStart; - this.onStop = onStop; Owner = owner; } public void Start() { - onStart?.Invoke(this); Track.Restart(); Started?.Invoke(); } public void Stop() { - onStop?.Invoke(); Track.Stop(); Stopped?.Invoke(); } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 59a088d954..4189468b77 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -15,9 +14,7 @@ namespace osu.Game.Audio { public class PreviewTrackManager : Component { - private Action onTrackStart; - private Action onTrackStop; - + private AudioManager audio; private TrackManager trackManager; private BindableDouble muteBindable; @@ -27,32 +24,36 @@ namespace osu.Game.Audio private void load(AudioManager audio, FrameworkConfigManager config) { trackManager = new TrackManager(new OnlineStore()); - muteBindable = new BindableDouble(); + this.audio = audio; audio.AddItem(trackManager); - config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); - onTrackStart = track => - { - CurrentTrack?.Stop(); - audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); - CurrentTrack = track; - }; - onTrackStop = () => - { - audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); - CurrentTrack = null; - }; + config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); } - public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) => - new PreviewTrack( + public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) + { + var previewTrack = new PreviewTrack( trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), - onTrackStart, - onTrackStop, previewOwner); + previewTrack.Started += () => + { + CurrentTrack?.Stop(); + CurrentTrack = previewTrack; + audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable); + }; + + previewTrack.Stopped += () => + { + CurrentTrack = null; + audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); + }; + + return previewTrack; + } + protected override void Update() { if (CurrentTrack?.Track.HasCompleted ?? false) From 97b473ef30ce254cadc75c76bc1630bc1c2186e3 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 16:23:11 -0300 Subject: [PATCH 049/186] Expose tabs and hide beatmap select button in Header. --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 12 +++++++++--- osu.Game/Screens/Multi/Screens/Match/Match.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index 1d414e338c..7985ff5fcf 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -26,18 +27,21 @@ namespace osu.Game.Screens.Multi.Screens.Match private readonly Box tabStrip; private readonly UpdateableBeatmapSetCover cover; - public readonly OsuClickableContainer BeatmapButton; + public readonly PageTabControl Tabs; public BeatmapSetInfo BeatmapSet { set { cover.BeatmapSet = value; } } + public Action OnWantsSelectBeatmap; + public Header() { RelativeSizeAxes = Axes.X; Height = HEIGHT; + BeatmapSelectButton beatmapButton; Children = new Drawable[] { cover = new UpdateableBeatmapSetCover @@ -70,12 +74,12 @@ namespace osu.Game.Screens.Multi.Screens.Match RelativeSizeAxes = Axes.Y, Width = 200, Padding = new MarginPadding { Vertical = 5 }, - Child = BeatmapButton = new BeatmapSelectButton + Child = beatmapButton = new BeatmapSelectButton { RelativeSizeAxes = Axes.Both, }, }, - new PageTabControl + Tabs = new PageTabControl { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -84,6 +88,8 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }, }; + + beatmapButton.Action = () => OnWantsSelectBeatmap?.Invoke(); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 525682e9c5..47fe7b9145 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Multi.Screens.Match }, }; - header.BeatmapButton.Action = () => Push(new MatchSongSelect()); + header.OnWantsSelectBeatmap = () => Push(new MatchSongSelect()); nameBind.ValueChanged += n => info.Name = n; statusBind.ValueChanged += s => info.Status = s; availabilityBind.ValueChanged += a => info.Availability = a; From 507305742013cacec3dc54feeeb630fd44971dc2 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 16:34:03 -0300 Subject: [PATCH 050/186] Cleanup. --- osu.Game/Screens/Multi/Screens/Match/Header.cs | 2 +- osu.Game/Screens/Multi/Screens/Match/Participants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Multi/Screens/Match/Header.cs b/osu.Game/Screens/Multi/Screens/Match/Header.cs index 7985ff5fcf..19e9dc4ad4 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Header.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Header.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Multi.Screens.Match public BeatmapSetInfo BeatmapSet { - set { cover.BeatmapSet = value; } + set => cover.BeatmapSet = value; } public Action OnWantsSelectBeatmap; diff --git a/osu.Game/Screens/Multi/Screens/Match/Participants.cs b/osu.Game/Screens/Multi/Screens/Match/Participants.cs index 182aa1e04e..9fa90f8752 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Participants.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Participants.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Multi.Screens.Match public int? Max { - set { count.Max = value; } + set => count.Max = value; } public Participants() From da8b1f996fb127f8b92a34ab90c5c085a7a2a597 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 1 Jun 2018 17:16:35 -0300 Subject: [PATCH 051/186] Override Type in Match. --- osu.Game/Screens/Multi/Screens/Match/Match.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Multi/Screens/Match/Match.cs b/osu.Game/Screens/Multi/Screens/Match/Match.cs index 47fe7b9145..3c6f141bd3 100644 --- a/osu.Game/Screens/Multi/Screens/Match/Match.cs +++ b/osu.Game/Screens/Multi/Screens/Match/Match.cs @@ -27,6 +27,7 @@ namespace osu.Game.Screens.Multi.Screens.Match protected override Container TransitionContent => participants; + public override string Type => "room"; public override string Title => room.Name.Value; public Match(Room room) From 330ce1904122d4169104ae500ce5338e3ba584e5 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Fri, 1 Jun 2018 23:36:25 +0300 Subject: [PATCH 052/186] Make PreviewTrack a component and use LoadComponentAsync --- osu.Game/Audio/PreviewTrack.cs | 19 +++++++++++++++---- osu.Game/Audio/PreviewTrackManager.cs | 23 +++++++++-------------- osu.Game/Overlays/Direct/PlayButton.cs | 13 ++++++------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 1250d4864e..d8898dfede 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -2,25 +2,36 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using osu.Framework.Allocation; using osu.Framework.Audio.Track; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; namespace osu.Game.Audio { - public class PreviewTrack + public class PreviewTrack : Component { - public readonly Track Track; + public Track Track { get; private set; } public readonly OverlayContainer Owner; + private readonly BeatmapSetInfo beatmapSetInfo; + public event Action Stopped; public event Action Started; - public PreviewTrack(Track track, OverlayContainer owner) + public PreviewTrack(BeatmapSetInfo beatmapSetInfo, OverlayContainer owner) { - Track = track; + this.beatmapSetInfo = beatmapSetInfo; Owner = owner; } + [BackgroundDependencyLoader] + private void load(PreviewTrackManager previewTrackManager) + { + Track = previewTrackManager.Get(this, beatmapSetInfo); + } + public void Start() { Track.Restart(); diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index 4189468b77..a3da930af0 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -6,7 +6,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.IO.Stores; using osu.Game.Beatmaps; @@ -32,12 +31,16 @@ namespace osu.Game.Audio config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume); } - public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo, OverlayContainer previewOwner) + protected override void Update() { - var previewTrack = new PreviewTrack( - trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"), - previewOwner); + if (CurrentTrack?.Track.HasCompleted ?? false) + CurrentTrack.Stop(); + base.Update(); + } + + public Track Get(PreviewTrack previewTrack, BeatmapSetInfo beatmapSetInfo) + { previewTrack.Started += () => { CurrentTrack?.Stop(); @@ -51,15 +54,7 @@ namespace osu.Game.Audio audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); }; - return previewTrack; - } - - protected override void Update() - { - if (CurrentTrack?.Track.HasCompleted ?? false) - CurrentTrack.Stop(); - - base.Update(); + return trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3"); } } } diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index a5c9da4fba..36d1170380 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; @@ -104,18 +103,18 @@ namespace osu.Game.Overlays.Direct { if (Preview == null) { - Task.Run(() => - { - loading = true; - return Preview = previewTrackManager.Get(beatmapSet, parentOverlayContainer); - }) - .ContinueWith(t => + loading = true; + + LoadComponentAsync( + Preview = new PreviewTrack(beatmapSet, parentOverlayContainer), + t => { Preview.Started += () => Playing.Value = true; Preview.Stopped += () => Playing.Value = false; Preview.Start(); loading = false; }); + return true; } From 70120aa14c1018f1ecb18ecc5ed50852673f7fa3 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 2 Jun 2018 12:28:16 +0300 Subject: [PATCH 053/186] Remove unused previewTrackManager variable --- osu.Game/Overlays/Direct/PlayButton.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 36d1170380..92d1acbaa4 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -46,8 +46,6 @@ namespace osu.Game.Overlays.Direct } } - private PreviewTrackManager previewTrackManager; - private Color4 hoverColour; private readonly SpriteIcon icon; private readonly LoadingAnimation loadingAnimation; @@ -94,7 +92,6 @@ namespace osu.Game.Overlays.Direct private void load(OsuColour colour, PreviewTrackManager previewTrackManager) { hoverColour = colour.Yellow; - this.previewTrackManager = previewTrackManager; } protected override bool OnClick(InputState state) From 5bb6757cbdbc24cc130cb2cbea643353032c7ae6 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 2 Jun 2018 13:03:17 +0300 Subject: [PATCH 054/186] Remove unused previewTrackManager parameter --- osu.Game/Overlays/Direct/PlayButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 92d1acbaa4..dc8042a137 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Direct } [BackgroundDependencyLoader] - private void load(OsuColour colour, PreviewTrackManager previewTrackManager) + private void load(OsuColour colour) { hoverColour = colour.Yellow; } From 9b69e1825da552b934c539ee6b499fc2feb0864a Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Sat, 2 Jun 2018 22:06:45 +0300 Subject: [PATCH 055/186] Make PreviewTrack.owner private --- osu.Game/Audio/PreviewTrack.cs | 12 +++++++++--- osu.Game/Overlays/BeatmapSetOverlay.cs | 3 +-- osu.Game/Overlays/DirectOverlay.cs | 3 +-- osu.Game/Overlays/UserProfileOverlay.cs | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index d8898dfede..cfc47497d0 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -13,7 +13,7 @@ namespace osu.Game.Audio public class PreviewTrack : Component { public Track Track { get; private set; } - public readonly OverlayContainer Owner; + private readonly OverlayContainer owner; private readonly BeatmapSetInfo beatmapSetInfo; @@ -23,7 +23,7 @@ namespace osu.Game.Audio public PreviewTrack(BeatmapSetInfo beatmapSetInfo, OverlayContainer owner) { this.beatmapSetInfo = beatmapSetInfo; - Owner = owner; + this.owner = owner; } [BackgroundDependencyLoader] @@ -38,8 +38,14 @@ namespace osu.Game.Audio Started?.Invoke(); } - public void Stop() + /// + /// Stop preview playback + /// + /// An which is probably the owner of this + public void Stop(OverlayContainer source = null) { + if (source != null && owner != source) + return; Track.Stop(); Stopped?.Invoke(); } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index cccd51a621..234d91b9e6 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -127,8 +127,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - if (previewTrackManager.CurrentTrack?.Owner == this) - previewTrackManager.CurrentTrack?.Stop(); + previewTrackManager.CurrentTrack?.Stop(this); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null); } diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 72de8ebc84..406554eb5e 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -302,8 +302,7 @@ namespace osu.Game.Overlays protected override void PopOut() { - if (previewTrackManager.CurrentTrack?.Owner == this) - previewTrackManager.CurrentTrack?.Stop(); + previewTrackManager.CurrentTrack?.Stop(this); base.PopOut(); } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 04a93dea23..6a8dd30890 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -73,7 +73,7 @@ namespace osu.Game.Overlays protected override void PopOut() { base.PopOut(); - previewTrackManager.CurrentTrack?.Stop(); + previewTrackManager.CurrentTrack?.Stop(this); FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out); } From dd75cd973be81bc6ae960b36fed441f2b0e92891 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jun 2018 01:13:35 +0900 Subject: [PATCH 056/186] Show UI mouse cursor when hovering volume meters during gameplay Also adds a hover animation. --- osu.Game/Overlays/Volume/VolumeMeter.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 64106967f4..04a04bc86e 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.MathUtils; using osu.Game.Graphics; @@ -189,5 +190,18 @@ namespace osu.Game.Overlays.Volume } public bool OnReleased(GlobalAction action) => false; + + private const float transition_length = 500; + + protected override bool OnHover(InputState state) + { + this.ScaleTo(1.04f, transition_length, Easing.OutExpo); + return true; + } + + protected override void OnHoverLost(InputState state) + { + this.ScaleTo(1f, transition_length, Easing.OutExpo); + } } } From 17ba129e616764855f61d980e6396527fde05783 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jun 2018 01:14:43 +0900 Subject: [PATCH 057/186] Make volume controls stay open when hovered Closes #2743. --- osu.Game/Overlays/VolumeOverlay.cs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index f922c507f7..5a3d51c00a 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Input.Bindings; @@ -86,16 +87,10 @@ namespace osu.Game.Overlays { base.LoadComplete(); - volumeMeterMaster.Bindable.ValueChanged += _ => settingChanged(); - volumeMeterEffect.Bindable.ValueChanged += _ => settingChanged(); - volumeMeterMusic.Bindable.ValueChanged += _ => settingChanged(); - muteButton.Current.ValueChanged += _ => settingChanged(); - } - - private void settingChanged() - { - Show(); - schedulePopOut(); + volumeMeterMaster.Bindable.ValueChanged += _ => Show(); + volumeMeterEffect.Bindable.ValueChanged += _ => Show(); + volumeMeterMusic.Bindable.ValueChanged += _ => Show(); + muteButton.Current.ValueChanged += _ => Show(); } public bool Adjust(GlobalAction action) @@ -140,10 +135,22 @@ namespace osu.Game.Overlays this.FadeOut(100); } + protected override bool OnMouseMove(InputState state) + { + // keep the scheduled event correctly timed as long as we have movement. + schedulePopOut(); + return base.OnMouseMove(state); + } + private void schedulePopOut() { popOutDelegate?.Cancel(); - this.Delay(1000).Schedule(Hide, out popOutDelegate); + this.Delay(1000).Schedule(() => + { + // only actually hide if the mouse isn't within our bounds. + if (!ScreenSpaceDrawQuad.Contains(GetContainingInputManager().CurrentState.Mouse.Position)) + Hide(); + }, out popOutDelegate); } } } From 5e9a1961cb0f34897cb27106b7c8e8076621a8bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 7 Jun 2018 11:33:39 +0900 Subject: [PATCH 058/186] Greatly increase the playfield scroll speed adjust step It was so small previously that I believe many people didn't even realise it was working. --- osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 6f86d20295..231892bdd9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// The step increase/decrease of the span of time visible by the length of the scrolling axes. /// - private const double time_span_step = 50; + private const double time_span_step = 500; /// /// The span of time that is visible by the length of the scrolling axes. @@ -88,10 +88,10 @@ namespace osu.Game.Rulesets.UI.Scrolling switch (args.Key) { case Key.Minus: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 200, Easing.OutQuint); + this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 600, Easing.OutQuint); break; case Key.Plus: - this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 200, Easing.OutQuint); + this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 600, Easing.OutQuint); break; } } From 3033294df1a583097d64b0b35f954bba13d3b2b3 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Thu, 7 Jun 2018 14:30:11 +0300 Subject: [PATCH 059/186] Stop Preview on BeatmapSet change --- osu.Game/Overlays/Direct/PlayButton.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index dc8042a137..607d6d218f 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -29,6 +29,7 @@ namespace osu.Game.Overlays.Direct if (value == beatmapSet) return; beatmapSet = value; + Preview.Stop(parentOverlayContainer); Playing.Value = false; Preview = null; } From ab6699b1fb599c7d8d6da4f30afb7bd986c17494 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Thu, 7 Jun 2018 14:40:41 +0300 Subject: [PATCH 060/186] Stop DirectOverlay preview on search update --- osu.Game/Overlays/DirectOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index 406554eb5e..fb1be8e05e 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -273,6 +273,8 @@ namespace osu.Game.Overlays if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return; + previewTrackManager.CurrentTrack?.Stop(this); + getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value ?? string.Empty, ((FilterControl)Filter).Ruleset.Value, Filter.DisplayStyleControl.Dropdown.Current.Value, From 1fdbd2047151f42fb1f59fdb15fabfd423bf78e4 Mon Sep 17 00:00:00 2001 From: Roman Kapustin Date: Thu, 7 Jun 2018 14:50:21 +0300 Subject: [PATCH 061/186] Nullref quickfix in PlayButton --- osu.Game/Overlays/Direct/PlayButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs index 607d6d218f..94c3cb748f 100644 --- a/osu.Game/Overlays/Direct/PlayButton.cs +++ b/osu.Game/Overlays/Direct/PlayButton.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Direct if (value == beatmapSet) return; beatmapSet = value; - Preview.Stop(parentOverlayContainer); + Preview?.Stop(parentOverlayContainer); Playing.Value = false; Preview = null; } From d1e9dba4aa46ae45ec391a5d00dd827a12effa13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 12:21:12 +0900 Subject: [PATCH 062/186] Move beatmap lookup ability to new request --- .../API/Requests/GetBeatmapDetailsRequest.cs | 4 +--- .../Online/API/Requests/GetBeatmapRequest.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetBeatmapRequest.cs diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs index ab840d054f..e3865be5fb 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs @@ -10,13 +10,11 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; - public GetBeatmapDetailsRequest(BeatmapInfo beatmap) { this.beatmap = beatmap; } - protected override string Target => $@"beatmaps/{lookupString}"; + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}"; } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs new file mode 100644 index 0000000000..9958d252ab --- /dev/null +++ b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetBeatmapRequest : APIRequest + { + private readonly BeatmapInfo beatmap; + + private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; + + public GetBeatmapRequest(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + } + + protected override string Target => $@"beatmaps/{lookupString}"; + } +} From 8220e0c79ab20a81b15785924b044b24085bbae0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 12:46:34 +0900 Subject: [PATCH 063/186] Remove OnlineBeatmapSetID from BeatmapMetadata --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 2 +- osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs | 11 +++++++---- osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs | 2 -- osu.Game.Tests/Visual/TestCasePlaySongSelect.cs | 1 - osu.Game/Beatmaps/BeatmapManager.cs | 11 +++++------ osu.Game/Beatmaps/BeatmapMetadata.cs | 13 +------------ osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 1 - .../Online/API/Requests/Responses/APIBeatmap.cs | 8 ++++++-- .../Online/API/Requests/Responses/APIBeatmapSet.cs | 9 +++++++++ 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 4985aa9365..6a7a4eeaf7 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); - Assert.AreEqual(241526, metadata.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmapInfo.OnlineBeatmapSetID); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 489c38c420..053485273f 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index f9b055ed55..665229f8c3 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -48,11 +48,14 @@ namespace osu.Game.Tests.Beatmaps.IO { var reader = new ZipArchiveReader(osz); - BeatmapMetadata meta; - using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = Decoder.GetDecoder(stream).Decode(stream).Metadata; + Beatmap beatmap; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) + beatmap = Decoder.GetDecoder(stream).Decode(stream); + + var meta = beatmap.Metadata; + + Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 4679fca855..6d2b37d981 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -449,7 +449,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = id, // Create random metadata, then we can check if sorting works based on these Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Title = $"test set #{id}!", @@ -503,7 +502,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = id, // Create random metadata, then we can check if sorting works based on these Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Title = $"test set #{id}!", diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 10121738f1..dab7f7e037 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -122,7 +122,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = 1234 + i, // Create random metadata, then we can check if sorting works based on these Artist = "MONACA " + RNG.Next(0, 9), Title = "Black Song " + RNG.Next(0, 9), diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 806bcc4132..589c00638f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -306,22 +306,22 @@ namespace osu.Game.Beatmaps return hashable.ComputeSHA2Hash(); } - protected override BeatmapSetInfo CreateModel(ArchiveReader reader) + protected override BeatmapSetInfo CreateModel(ArchiveReader reader) { // let's make sure there are actually .osu files to import. string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu")); if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in this beatmap archive."); - BeatmapMetadata metadata; + Beatmap beatmap; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = Decoder.GetDecoder(stream).Decode(stream).Metadata; + beatmap = Decoder.GetDecoder(stream).Decode(stream); return new BeatmapSetInfo { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), - Metadata = metadata + Metadata = beatmap.Metadata }; } @@ -350,7 +350,6 @@ namespace osu.Game.Beatmaps // ensure we have the same online set ID as the set itself. beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID; - beatmap.BeatmapInfo.Metadata.OnlineBeatmapSetID = model.OnlineBeatmapSetID; // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 34147c18d2..6c1bcd0531 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -17,16 +17,6 @@ namespace osu.Game.Beatmaps [JsonIgnore] public int ID { get; set; } - private int? onlineBeatmapSetID; - - [NotMapped] - [JsonProperty(@"id")] - public int? OnlineBeatmapSetID - { - get { return onlineBeatmapSetID; } - set { onlineBeatmapSetID = value > 0 ? value : null; } - } - public string Title { get; set; } public string TitleUnicode { get; set; } public string Artist { get; set; } @@ -82,8 +72,7 @@ namespace osu.Game.Beatmaps if (other == null) return false; - return onlineBeatmapSetID == other.onlineBeatmapSetID - && Title == other.Title + return Title == other.Title && TitleUnicode == other.TitleUnicode && Artist == other.Artist && ArtistUnicode == other.ArtistUnicode diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index a83ac26fb3..ee2c608fd7 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -208,7 +208,6 @@ namespace osu.Game.Beatmaps.Formats break; case @"BeatmapSetID": beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); - metadata.OnlineBeatmapSetID = int.Parse(pair.Value); break; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index f75d320a46..01a4453657 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -10,7 +10,10 @@ namespace osu.Game.Online.API.Requests.Responses public class APIBeatmap : BeatmapMetadata { [JsonProperty(@"id")] - private int onlineBeatmapID { get; set; } + public int OnlineBeatmapID { get; set; } + + [JsonProperty(@"beatmapset_id")] + public int OnlineBeatmapSetID { get; set; } [JsonProperty(@"playcount")] private int playCount { get; set; } @@ -55,7 +58,8 @@ namespace osu.Game.Online.API.Requests.Responses Metadata = this, Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, - OnlineBeatmapID = onlineBeatmapID, + OnlineBeatmapID = OnlineBeatmapID, + OnlineBeatmapSetID = OnlineBeatmapSetID, Version = version, BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index f57de016a2..3b6bb565b0 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -15,6 +15,15 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"covers")] private BeatmapSetOnlineCovers covers { get; set; } + private int? onlineBeatmapSetID; + + [JsonProperty(@"id")] + public int? OnlineBeatmapSetID + { + get { return onlineBeatmapSetID; } + set { onlineBeatmapSetID = value > 0 ? value : null; } + } + [JsonProperty(@"preview_url")] private string preview { get; set; } From b265f02d56025665f86b216e9b08e277b32b5c2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 14:37:27 +0900 Subject: [PATCH 064/186] Add comment about scheduled invocation --- osu.Game/Online/API/APIRequest.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index dfd181b98a..c89f8ce292 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -24,6 +24,10 @@ namespace osu.Game.Online.API Success?.Invoke(((JsonWebRequest)WebRequest).ResponseObject); } + /// + /// Invoked on successful completion of an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public new event APISuccessHandler Success; } @@ -52,7 +56,16 @@ namespace osu.Game.Online.API protected APIAccess API; protected WebRequest WebRequest; + /// + /// Invoked on successful completion of an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public event APISuccessHandler Success; + + /// + /// Invoked on failure to complete an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public event APIFailureHandler Failure; private bool cancelled; From 21c8ef576c50bccea501e36743d6c0b5fc5edbe4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 14:37:48 +0900 Subject: [PATCH 065/186] Expose result for synchronous consumption --- osu.Game/Online/API/APIRequest.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index c89f8ce292..adbedb2aac 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -14,15 +14,14 @@ namespace osu.Game.Online.API { protected override WebRequest CreateWebRequest() => new JsonWebRequest(Uri); + public T Result => ((JsonWebRequest)WebRequest).ResponseObject; + protected APIRequest() { base.Success += onSuccess; } - private void onSuccess() - { - Success?.Invoke(((JsonWebRequest)WebRequest).ResponseObject); - } + private void onSuccess() => Success?.Invoke(Result); /// /// Invoked on successful completion of an API request. From e8455dc1e41ca92d0f9d1118af1187da88aba740 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 14:38:04 +0900 Subject: [PATCH 066/186] Fix incorrect hash usage --- osu.Game/Online/API/Requests/GetBeatmapRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs index 9958d252ab..9d254ce29d 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; + private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.MD5Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; public GetBeatmapRequest(BeatmapInfo beatmap) { From 955a78e76d491e438c4f54b4e26f21381faf2826 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 15:26:27 +0900 Subject: [PATCH 067/186] Remove OnlineBeatmapSetID from BeatmapInfo It should now be retrieved via the linked BeatmapSetInfo --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 2 +- osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- .../Visual/TestCaseBeatmapScoresContainer.cs | 2 +- osu.Game/Beatmaps/BeatmapInfo.cs | 14 ++------------ osu.Game/Beatmaps/BeatmapManager.cs | 9 +++------ osu.Game/Beatmaps/BeatmapSetInfo.cs | 6 +++--- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 6 ++++-- .../Online/API/Requests/Responses/APIBeatmap.cs | 5 ++++- .../Requests/Responses/APIUserMostPlayedBeatmap.cs | 1 - .../Profile/Sections/BeatmapMetadataContainer.cs | 2 +- 11 files changed, 21 insertions(+), 30 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 6a7a4eeaf7..1628423fe8 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); - Assert.AreEqual(241526, beatmapInfo.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 053485273f..b834be71f1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 665229f8c3..0039516c0c 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Beatmaps.IO var meta = beatmap.Metadata; - Assert.AreEqual(241526, beatmap.BeatmapInfo.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 3f63bacfa6..d3098864f4 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual AddStep("remove scores", () => scoresContainer.Scores = null); AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); - AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapSetID = 1, OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); + AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); scores = new[] diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 40d62103a8..3afc3c4d32 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -23,7 +23,6 @@ namespace osu.Game.Beatmaps public int BeatmapVersion; private int? onlineBeatmapID; - private int? onlineBeatmapSetID; [JsonProperty("id")] public int? OnlineBeatmapID @@ -32,19 +31,10 @@ namespace osu.Game.Beatmaps set { onlineBeatmapID = value > 0 ? value : null; } } - [JsonProperty("beatmapset_id")] - [NotMapped] - public int? OnlineBeatmapSetID - { - get { return onlineBeatmapSetID; } - set { onlineBeatmapSetID = value > 0 ? value : null; } - } - [JsonIgnore] public int BeatmapSetInfoID { get; set; } [Required] - [JsonIgnore] public BeatmapSetInfo BeatmapSet { get; set; } public BeatmapMetadata Metadata { get; set; } @@ -141,8 +131,8 @@ namespace osu.Game.Beatmaps (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile; public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && - BeatmapSet.Hash == other.BeatmapSet.Hash && - (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; + BeatmapSet.Hash == other.BeatmapSet.Hash && + (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; /// /// Returns a shallow-clone of this . diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 589c00638f..526f2488ea 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -81,7 +81,7 @@ namespace osu.Game.Beatmaps protected override void Populate(BeatmapSetInfo model, ArchiveReader archive) { - model.Beatmaps = createBeatmapDifficulties(model, archive); + model.Beatmaps = createBeatmapDifficulties(archive); // remove metadata from difficulties where it matches the set foreach (BeatmapInfo b in model.Beatmaps) @@ -318,7 +318,7 @@ namespace osu.Game.Beatmaps return new BeatmapSetInfo { - OnlineBeatmapSetID = beatmap.BeatmapInfo.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), Metadata = beatmap.Metadata @@ -328,7 +328,7 @@ namespace osu.Game.Beatmaps /// /// Create all required s for the provided archive. /// - private List createBeatmapDifficulties(BeatmapSetInfo model, ArchiveReader reader) + private List createBeatmapDifficulties(ArchiveReader reader) { var beatmapInfos = new List(); @@ -348,9 +348,6 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - // ensure we have the same online set ID as the set itself. - beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID; - // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) beatmap.BeatmapInfo.OnlineBeatmapID = null; diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index fa08c6cb68..ed8fbdbb26 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -22,18 +22,18 @@ namespace osu.Game.Beatmaps [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } - public double MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty); + public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0; [NotMapped] public bool DeletePending { get; set; } public string Hash { get; set; } - public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; + public string StoryboardFile => Files?.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; public List Files { get; set; } - public override string ToString() => Metadata.ToString(); + public override string ToString() => Metadata?.ToString() ?? base.ToString(); public bool Protected { get; set; } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index ee2c608fd7..581207607a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -34,7 +34,8 @@ namespace osu.Game.Beatmaps.Formats private readonly int offset; - public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version) + public LegacyBeatmapDecoder(int version = LATEST_VERSION) + : base(version) { // BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off) offset = FormatVersion < 5 ? 24 : 0; @@ -135,6 +136,7 @@ namespace osu.Game.Beatmaps.Formats parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser(); break; } + break; case @"LetterboxInBreaks": beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; @@ -207,7 +209,7 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = int.Parse(pair.Value) }; break; } } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 01a4453657..99e4392374 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -59,7 +59,10 @@ namespace osu.Game.Online.API.Requests.Responses Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, OnlineBeatmapID = OnlineBeatmapID, - OnlineBeatmapSetID = OnlineBeatmapSetID, + BeatmapSet = new BeatmapSetInfo + { + OnlineBeatmapSetID = OnlineBeatmapSetID, + }, Version = version, BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs index d49613eab7..8a5aea9e97 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs @@ -25,7 +25,6 @@ namespace osu.Game.Online.API.Requests.Responses { BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); beatmap.BeatmapSet = setInfo; - beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID; beatmap.Metadata = setInfo.Metadata; return beatmap; } diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 97079c77f3..359bfc7564 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections { Action = () => { - if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value); + if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value); }; Child = new FillFlowContainer From a775d00bd87bc96c75e31ab4890db3d20b99b5d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 15:59:45 +0900 Subject: [PATCH 068/186] Add online fetch support for online IDs --- osu.Game/Beatmaps/BeatmapManager.cs | 69 +++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 14 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 526f2488ea..895b47d62b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -83,10 +83,29 @@ namespace osu.Game.Beatmaps { model.Beatmaps = createBeatmapDifficulties(archive); - // remove metadata from difficulties where it matches the set foreach (BeatmapInfo b in model.Beatmaps) + { + // remove metadata from difficulties where it matches the set if (model.Metadata.Equals(b.Metadata)) b.Metadata = null; + + // by setting the model here, we can update the noline set id below. + b.BeatmapSet = model; + + fetchAndPopulateOnlineIDs(b); + } + + // check if a set already exists with the same online id, delete if it does. + if (model.OnlineBeatmapSetID != null) + { + var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); + if (existingOnlineId != null) + { + Delete(existingOnlineId); + beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); + Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); + } + } } protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model) @@ -99,18 +118,6 @@ namespace osu.Game.Beatmaps return existingHashMatch; } - // check if a set already exists with the same online id - if (model.OnlineBeatmapSetID != null) - { - var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); - if (existingOnlineId != null) - { - Delete(existingOnlineId); - beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); - Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); - } - } - return null; } @@ -318,7 +325,7 @@ namespace osu.Game.Beatmaps return new BeatmapSetInfo { - OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), Metadata = beatmap.Metadata @@ -372,6 +379,40 @@ namespace osu.Game.Beatmaps return beatmapInfos; } + /// + /// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties. + /// + /// The beatmap to populate. + /// Whether to re-query if the provided beatmap already has populated values. + /// True if population was successful. + private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false) + { + if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) + return true; + + Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database); + + try + { + var req = new GetBeatmapRequest(beatmap); + + req.Perform(api); + + var res = req.Result; + + Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database); + + beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID; + beatmap.OnlineBeatmapID = res.OnlineBeatmapID; + return true; + } + catch (Exception e) + { + Logger.Log($"Failed ({e})", LoggingTarget.Database); + return false; + } + } + /// /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation. /// From e1bc0fa552256ee256b12ce62865ebc832986023 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 8 Jun 2018 15:59:59 +0900 Subject: [PATCH 069/186] Fix csproj file ending line --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 363fc7d7bb..f5ff1fbd53 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,4 +23,4 @@ - + \ No newline at end of file From b219c171159e67601351441f317dfe751e656a89 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 12:57:26 +0900 Subject: [PATCH 070/186] Move dependency creation under ctor --- osu.Game/Rulesets/UI/RulesetContainer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 384b71cccc..561e77b0c9 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -73,11 +73,6 @@ namespace osu.Game.Rulesets.UI private IRulesetConfigManager rulesetConfig; private OnScreenDisplay onScreenDisplay; - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) - => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - /// /// A visual representation of a . /// @@ -104,6 +99,11 @@ namespace osu.Game.Rulesets.UI } } + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + public abstract ScoreProcessor CreateScoreProcessor(); /// From 63ec36b3be32b58af43a5e5a99ebc875b9ad5f68 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 12:57:56 +0900 Subject: [PATCH 071/186] Explicitly handle null settings case + add annotations --- osu.Game/Rulesets/UI/RulesetContainer.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 561e77b0c9..f604e876e7 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Configuration; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; @@ -86,16 +87,19 @@ namespace osu.Game.Rulesets.UI } [BackgroundDependencyLoader(true)] - private void load(OnScreenDisplay onScreenDisplay, SettingsStore settings) + private void load([CanBeNull] OnScreenDisplay onScreenDisplay, [CanBeNull] SettingsStore settings) { this.onScreenDisplay = onScreenDisplay; - rulesetConfig = CreateConfig(Ruleset, settings); - - if (rulesetConfig != null) + if (settings != null) { - dependencies.Cache(rulesetConfig); - onScreenDisplay?.BeginTracking(this, rulesetConfig); + rulesetConfig = CreateConfig(Ruleset, settings); + + if (rulesetConfig != null) + { + dependencies.Cache(rulesetConfig); + onScreenDisplay?.BeginTracking(this, rulesetConfig); + } } } From 22e8a0bb6ec70a12890e39f98b122528fb81aee6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 13:13:36 +0900 Subject: [PATCH 072/186] Make ruleset config manager variants nullable --- osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs | 2 +- osu.Game/Configuration/DatabasedConfigManager.cs | 4 ++-- osu.Game/Rulesets/Configuration/RulesetConfigManager.cs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs index ea5f590bd1..d9e360081d 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Configuration { public class ManiaConfigManager : RulesetConfigManager { - public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) + public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) : base(settings, ruleset, variant) { } diff --git a/osu.Game/Configuration/DatabasedConfigManager.cs b/osu.Game/Configuration/DatabasedConfigManager.cs index 0ef0589dff..0ede6de0f2 100644 --- a/osu.Game/Configuration/DatabasedConfigManager.cs +++ b/osu.Game/Configuration/DatabasedConfigManager.cs @@ -13,13 +13,13 @@ namespace osu.Game.Configuration { private readonly SettingsStore settings; - private readonly int variant; + private readonly int? variant; private readonly List databasedSettings; private readonly RulesetInfo ruleset; - protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int variant = 0) + protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int? variant = null) { this.settings = settings; this.ruleset = ruleset; diff --git a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs index 4ecf1eefb2..74cece5154 100644 --- a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs +++ b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs @@ -8,7 +8,8 @@ namespace osu.Game.Rulesets.Configuration public abstract class RulesetConfigManager : DatabasedConfigManager, IRulesetConfigManager where T : struct { - protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) : base(settings, ruleset, variant) + protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) + : base(settings, ruleset, variant) { } } From eca016ec6c8a54bf37ebf1afcb6b70ba8980d563 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 13:17:08 +0900 Subject: [PATCH 073/186] Move ruleset config managers to Ruleset --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 5 +++++ osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs | 5 ----- osu.Game/Rulesets/Ruleset.cs | 8 ++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 4 +--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 5f803e3406..e671a3fb14 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -15,8 +15,11 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Beatmaps.Legacy; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Scoring; @@ -150,6 +153,8 @@ namespace osu.Game.Rulesets.Mania public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); + public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaConfigManager(settings, RulesetInfo); + public ManiaRuleset(RulesetInfo rulesetInfo = null) : base(rulesetInfo) { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 7123aab901..a3145d6035 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -10,12 +10,9 @@ using osu.Framework.Input; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Configuration; using osu.Game.Input.Handlers; -using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Mods; -using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Replays; @@ -103,7 +100,5 @@ namespace osu.Game.Rulesets.Mania.UI protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); - - protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 395eeab419..f7f9d59dc6 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -15,6 +15,8 @@ using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Beatmaps.Legacy; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; namespace osu.Game.Rulesets @@ -71,6 +73,12 @@ namespace osu.Game.Rulesets public virtual SettingsSubsection CreateSettings() => null; + /// + /// Creates the for this . + /// + /// The to store the settings. + public virtual IRulesetConfigManager CreateConfig(SettingsStore settings) => null; + /// /// Do not override this unless you are a legacy mode. /// diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index f604e876e7..875745edfb 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.UI if (settings != null) { - rulesetConfig = CreateConfig(Ruleset, settings); + rulesetConfig = Ruleset.CreateConfig(settings); if (rulesetConfig != null) { @@ -140,8 +140,6 @@ namespace osu.Game.Rulesets.UI /// protected virtual CursorContainer CreateCursor() => null; - protected virtual IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => null; - /// /// Creates a Playfield. /// From f4fbf27d42877f4c769186e972e09f40f41866e3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 13:28:50 +0900 Subject: [PATCH 074/186] Give ruleset settings a ruleset-specific config manager --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuSettings.cs | 7 +++- .../Settings/RulesetSettingsSubsection.cs | 36 +++++++++++++++++++ osu.Game/Rulesets/Ruleset.cs | 2 +- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index b920e889ce..6ab75d008f 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu public override string ShortName => "osu"; - public override SettingsSubsection CreateSettings() => new OsuSettings(); + public override RulesetSettingsSubsection CreateSettings() => new OsuSettings(this); public override int? LegacyID => 0; diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettings.cs b/osu.Game.Rulesets.Osu/UI/OsuSettings.cs index 31ad6701fd..25c009b117 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettings.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettings.cs @@ -8,10 +8,15 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Rulesets.Osu.UI { - public class OsuSettings : SettingsSubsection + public class OsuSettings : RulesetSettingsSubsection { protected override string Header => "osu!"; + public OsuSettings(Ruleset ruleset) + : base(ruleset) + { + } + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { diff --git a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs new file mode 100644 index 0000000000..8f8c18d1f0 --- /dev/null +++ b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Game.Configuration; +using osu.Game.Rulesets; + +namespace osu.Game.Overlays.Settings +{ + /// + /// A which provides subclasses with the + /// from the 's . + /// + public abstract class RulesetSettingsSubsection : SettingsSubsection + { + private readonly Ruleset ruleset; + + protected RulesetSettingsSubsection(Ruleset ruleset) + { + this.ruleset = ruleset; + } + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + + var config = ruleset.CreateConfig(dependencies.Get()); + if (config != null) + dependencies.Cache(config); + + return dependencies; + } + } +} diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index f7f9d59dc6..a39e8bb8d4 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets public abstract string Description { get; } - public virtual SettingsSubsection CreateSettings() => null; + public virtual RulesetSettingsSubsection CreateSettings() => null; /// /// Creates the for this . From be01dbae3ac4635706caf82cc4be9e19533e00d7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 14:36:56 +0900 Subject: [PATCH 075/186] Move ruleset dependency caching to CreateLocalDependencies In some cases we may want to refer to the cached configmanager dependency from subclasses. This prevents injection errors when doing so. --- osu.Game/Rulesets/UI/RulesetContainer.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 875745edfb..a7005f1d5e 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -13,7 +13,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Configuration; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; @@ -86,11 +85,13 @@ namespace osu.Game.Rulesets.UI Cursor = CreateCursor(); } - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OnScreenDisplay onScreenDisplay, [CanBeNull] SettingsStore settings) + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) { - this.onScreenDisplay = onScreenDisplay; + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + onScreenDisplay = dependencies.Get(); + + var settings = dependencies.Get(); if (settings != null) { rulesetConfig = Ruleset.CreateConfig(settings); @@ -101,13 +102,10 @@ namespace osu.Game.Rulesets.UI onScreenDisplay?.BeginTracking(this, rulesetConfig); } } + + return dependencies; } - private DependencyContainer dependencies; - - protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) - => dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - public abstract ScoreProcessor CreateScoreProcessor(); /// From 14b75309944a02d0ad8ff7622603ec0d4dbdb235 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 15:07:42 +0900 Subject: [PATCH 076/186] Use a global ruleset config cache --- osu.Game/OsuGameBase.cs | 3 ++ .../Settings/RulesetSettingsSubsection.cs | 3 +- osu.Game/Rulesets/RulesetConfigCache.cs | 43 +++++++++++++++++++ osu.Game/Rulesets/UI/RulesetContainer.cs | 13 ++---- 4 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Rulesets/RulesetConfigCache.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b968d7d4d0..a5779a2293 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -56,6 +56,8 @@ namespace osu.Game protected SettingsStore SettingsStore; + protected RulesetConfigCache RulesetConfigCache; + protected MenuCursorContainer MenuCursorContainer; private Container content; @@ -123,6 +125,7 @@ namespace osu.Game dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory, Host, BeatmapManager, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); + dependencies.Cache(RulesetConfigCache = new RulesetConfigCache(SettingsStore)); dependencies.Cache(new OsuColour()); fileImporters.Add(BeatmapManager); diff --git a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs index 8f8c18d1f0..05104018cd 100644 --- a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Game.Configuration; using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings @@ -26,7 +25,7 @@ namespace osu.Game.Overlays.Settings { dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); - var config = ruleset.CreateConfig(dependencies.Get()); + var config = dependencies.Get().GetConfigFor(ruleset); if (config != null) dependencies.Cache(config); diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs new file mode 100644 index 0000000000..52c40465f3 --- /dev/null +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Configuration; +using osu.Game.Rulesets.Configuration; + +namespace osu.Game.Rulesets +{ + /// + /// A cache that provides a single per-ruleset + /// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings. + /// + public class RulesetConfigCache : Component + { + private readonly Dictionary configCache = new Dictionary(); + private readonly SettingsStore settingsStore; + + public RulesetConfigCache(SettingsStore settingsStore) + { + this.settingsStore = settingsStore; + } + + /// + /// Retrieves the for a . + /// + /// The to retrieve the for. + /// The defined by , null if doesn't define one. + /// If doesn't have a valid . + public IRulesetConfigManager GetConfigFor(Ruleset ruleset) + { + if (ruleset.RulesetInfo.ID == null) + throw new InvalidOperationException("The provided ruleset doesn't have a valid id."); + + if (configCache.TryGetValue(ruleset.RulesetInfo.ID.Value, out var existing)) + return existing; + + return configCache[ruleset.RulesetInfo.ID.Value] = ruleset.CreateConfig(settingsStore); + } + } +} diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index a7005f1d5e..15383946e8 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -91,16 +91,11 @@ namespace osu.Game.Rulesets.UI onScreenDisplay = dependencies.Get(); - var settings = dependencies.Get(); - if (settings != null) + rulesetConfig = dependencies.Get().GetConfigFor(Ruleset); + if (rulesetConfig != null) { - rulesetConfig = Ruleset.CreateConfig(settings); - - if (rulesetConfig != null) - { - dependencies.Cache(rulesetConfig); - onScreenDisplay?.BeginTracking(this, rulesetConfig); - } + dependencies.Cache(rulesetConfig); + onScreenDisplay?.BeginTracking(this, rulesetConfig); } return dependencies; From b51e714ae5d5997bcc952ba8dc6cd53acf08c318 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 15:44:59 +0900 Subject: [PATCH 077/186] Fix xmldoc --- osu.Game/Rulesets/RulesetConfigCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs index 52c40465f3..7e83ba0961 100644 --- a/osu.Game/Rulesets/RulesetConfigCache.cs +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Configuration; namespace osu.Game.Rulesets { /// - /// A cache that provides a single per-ruleset + /// A cache that provides a single per-ruleset. /// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings. /// public class RulesetConfigCache : Component From 8f3215f5a0b251f29e4863e50b396e91624e33e3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 20:42:04 +0900 Subject: [PATCH 078/186] Make sure taiko hitexplosions expire and get removed --- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 4 +++- osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index ee2c1d5ad5..4dd0ba4d3d 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class HitExplosion : CircularContainer { + public override bool RemoveWhenNotAlive => true; + public readonly DrawableHitObject JudgedObject; private readonly Box innerFill; @@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.UI this.ScaleTo(3f, 1000, Easing.OutQuint); this.FadeOut(500); - Expire(); + Expire(true); } /// diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index ac3cf8305a..287d59972a 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Taiko.UI { public class KiaiHitExplosion : CircularContainer { + public override bool RemoveWhenNotAlive => true; + public readonly DrawableHitObject JudgedObject; private readonly bool isRim; @@ -62,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.UI this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint); this.FadeOut(250); - Expire(); + Expire(true); } } } From 22dfe46572b2f73a0fbb790688d41a8a78d873d5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 11 Jun 2018 21:45:19 +0900 Subject: [PATCH 079/186] Make taiko hitobject properly unproxy when rewound --- .../Objects/Drawables/DrawableHit.cs | 4 ++ .../Objects/Drawables/DrawableSwell.cs | 20 +++---- .../Drawables/DrawableTaikoHitObject.cs | 60 +++++++++++++++++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 20 +------ 4 files changed, 70 insertions(+), 34 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index d923b2dcdf..cca2753524 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -86,6 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (State.Value) { case ArmedState.Idle: + UnproxyContent(); this.Delay(HitObject.HitWindows.HalfWindowFor(HitResult.Miss)).Expire(); break; case ArmedState.Miss: @@ -93,6 +94,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables .Expire(); break; case ArmedState.Hit: + if (X >= -0.05f) + ProxyContent(); + var flash = circlePiece?.FlashBox; if (flash != null) { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 33cc29bccf..1f571544d8 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -20,12 +20,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public class DrawableSwell : DrawableTaikoHitObject { - /// - /// Invoked when the swell has reached the hit target, i.e. when CurrentTime >= StartTime. - /// This is only ever invoked once. - /// - public event Action OnStart; - private const float target_ring_thick_border = 1.4f; private const float target_ring_thin_border = 1f; private const float target_ring_scale = 5f; @@ -40,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private int userHits; - private bool hasStarted; + private bool hasProxied; private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) @@ -48,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { FillMode = FillMode.Fit; - AddInternal(bodyContainer = new Container + Content.Add(bodyContainer = new Container { RelativeSizeAxes = Axes.Both, Depth = 1, @@ -177,6 +171,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { + case ArmedState.Idle: + hasProxied = false; + UnproxyContent(); + break; case ArmedState.Hit: bodyContainer.Delay(untilJudgement).ScaleTo(1.4f, out_transition_time); break; @@ -195,10 +193,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables X = Math.Max(0, X); double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime && !hasStarted) + if (t == HitObject.StartTime && !hasProxied) { - OnStart?.Invoke(); - hasStarted = true; + ProxyContent(); + hasProxied = true; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 971fd8854d..c07ee3a0fd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -9,10 +9,62 @@ using OpenTK; using System.Linq; using osu.Game.Audio; using System.Collections.Generic; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + { + protected readonly Container Content; + public readonly Container ProxiedContent; + + private readonly Container nonProxiedContent; + + protected DrawableTaikoHitObject(TaikoHitObject hitObject) + : base(hitObject) + { + InternalChildren = new[] + { + nonProxiedContent = new Container + { + RelativeSizeAxes = Axes.Both, + Child = Content = new Container { RelativeSizeAxes = Axes.Both } + }, + ProxiedContent = new Container { RelativeSizeAxes = Axes.Both } + }; + } + + /// + /// is proxied into an upper layer. We don't want to get masked away otherwise would too. + /// + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + + /// + /// Moves to a layer proxied above the playfield. + /// + protected void ProxyContent() + { + nonProxiedContent.Remove(Content); + ProxiedContent.Remove(Content); + ProxiedContent.Add(Content); + } + + /// + /// Moves to the normal hitobject layer. + /// + protected void UnproxyContent() + { + ProxiedContent.Remove(Content); + nonProxiedContent.Remove(Content); + nonProxiedContent.Add(Content); + } + + public abstract bool OnPressed(TaikoAction action); + public virtual bool OnReleased(TaikoAction action) => false; + } + + public abstract class DrawableTaikoHitObject : DrawableTaikoHitObject where TaikoHitType : TaikoHitObject { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); @@ -34,7 +86,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both; Size = BaseSize = new Vector2(HitObject.IsStrong ? TaikoHitObject.DEFAULT_STRONG_SIZE : TaikoHitObject.DEFAULT_SIZE); - InternalChild = MainPiece = CreateMainPiece(); + Content.Add(MainPiece = CreateMainPiece()); MainPiece.KiaiMode = HitObject.Kiai; } @@ -44,9 +96,5 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override string SampleNamespace => "Taiko"; protected virtual TaikoPiece CreateMainPiece() => new CirclePiece(); - - public abstract bool OnPressed(TaikoAction action); - - public virtual bool OnReleased(TaikoAction action) => false; } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 417a7c2581..c638f807fe 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -216,10 +216,9 @@ namespace osu.Game.Rulesets.Taiko.UI if (barline != null) barlineContainer.Add(barline.CreateProxy()); - // Swells should be moved at the very top of the playfield when they reach the hit target - var swell = h as DrawableSwell; - if (swell != null) - swell.OnStart += () => topLevelHitContainer.Add(swell.CreateProxy()); + var taikoObject = h as DrawableTaikoHitObject; + if (taikoObject != null) + topLevelHitContainer.Add(taikoObject.ProxiedContent.CreateProxy()); } internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) @@ -244,19 +243,6 @@ namespace osu.Game.Rulesets.Taiko.UI hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == judgedObject)?.VisualiseSecondHit(); else { - if (judgedObject.X >= -0.05f && judgedObject is DrawableHit) - { - // If we're far enough away from the left stage, we should bring outselves in front of it - // Todo: The following try-catch is temporary for replay rewinding support - try - { - topLevelHitContainer.Add(judgedObject.CreateProxy()); - } - catch - { - } - } - hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim)); if (judgedObject.HitObject.Kiai) From 1b12820de9e8529df794cc3d1396ba9e4d954c29 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Mon, 11 Jun 2018 21:54:11 +0900 Subject: [PATCH 080/186] Restore a removed comment --- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index cca2753524..519b56a3ed 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables .Expire(); break; case ArmedState.Hit: + // If we're far enough away from the left stage, we should bring outselves in front of it if (X >= -0.05f) ProxyContent(); From 7651819fb0ea29f7f636cdd4e4e42fcfa680e24b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 12:53:53 +0900 Subject: [PATCH 081/186] Add same change to mania's hit explosions --- osu.Game.Rulesets.Mania/UI/HitExplosion.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs index f19c3a811b..bf8db63137 100644 --- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs @@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Mania.UI { internal class HitExplosion : CompositeDrawable { + public override bool RemoveWhenNotAlive => true; + private readonly CircularContainer circle; public HitExplosion(DrawableHitObject judgedObject) From b90cdfbfd166aeb8fc26ad1bf8f51ff8d1c9b3d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 14:33:33 +0900 Subject: [PATCH 082/186] Remove unused variable --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 0a2e549509..c0557982fb 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual public TestCaseEditorComposeTimeline() { - TimelineArea timelineArea; - Children = new Drawable[] { new MusicController From 6ceac8ab0a316437d1dfed2c133927e2496c71f3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 24 May 2018 15:23:59 +0900 Subject: [PATCH 083/186] Add a centre marker to the timeline --- .../Visual/TestCaseEditorComposeTimeline.cs | 9 +++- .../Screens/Compose/Timeline/CentreMarker.cs | 52 +++++++++++++++++++ .../Edit/Screens/Compose/Timeline/Timeline.cs | 6 +++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index c0557982fb..d731ef973a 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -15,7 +15,14 @@ namespace osu.Game.Tests.Visual [TestFixture] public class TestCaseEditorComposeTimeline : EditorClockTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) }; + public override IReadOnlyList RequiredTypes => new[] + { + typeof(TimelineArea), + typeof(Timeline), + typeof(BeatmapWaveformGraph), + typeof(TimelineButton), + typeof(CentreMarker) + }; public TestCaseEditorComposeTimeline() { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs new file mode 100644 index 0000000000..8e932f307d --- /dev/null +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using OpenTK; + +namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +{ + public class CentreMarker : CompositeDrawable + { + private const float triangle_width = 20; + private const float triangle_height = 10; + private const float bar_width = 2; + + public CentreMarker() + { + RelativeSizeAxes = Axes.Y; + Size = new Vector2(20, 1); + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChildren = new Drawable[] + { + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Width = bar_width, + }, + new Triangle + { + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + Size = new Vector2(triangle_width, triangle_height), + Scale = new Vector2(1, -1) + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Red; + } + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index daf67ed7f0..d5f47f5e04 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -41,6 +41,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline Depth = float.MaxValue }; + // We don't want the centre marker to scroll + AddInternal(new CentreMarker()); + + // Make sure that the scrollbar is above the centre marker + ChangeInternalChildDepth(Scrollbar, -1); + WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); Beatmap.BindTo(beatmap); From 7dfe171869ed7b0596c30620f55ea834636628c2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 14:31:12 +0900 Subject: [PATCH 084/186] Fix rebase error --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index d731ef973a..a89c5767fc 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -19,7 +19,6 @@ namespace osu.Game.Tests.Visual { typeof(TimelineArea), typeof(Timeline), - typeof(BeatmapWaveformGraph), typeof(TimelineButton), typeof(CentreMarker) }; From aaf2f66594527f0d912bedaf72e79c22e4916b5c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 15:49:42 +0900 Subject: [PATCH 085/186] Make scrolling only zoom the timeline --- .../Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index 035e6a0804..ed26c28c80 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -99,10 +99,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnScroll(InputState state) { - if (!state.Keyboard.ControlPressed) + if (state.Mouse.HasPreciseScroll) return base.OnScroll(state); - - setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.X, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); + setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.Y, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); return true; } From 3b396e38caf1211eb3b6645f81b22e86092b7904 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 15:51:48 +0900 Subject: [PATCH 086/186] Hide the scrollbar --- .../Edit/Screens/Compose/Timeline/Timeline.cs | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index daf67ed7f0..3bd7a0b96b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline ZoomDuration = 200; ZoomEasing = Easing.OutQuint; Zoom = 10; + ScrollbarVisible = false; } private WaveformGraph waveform; @@ -150,35 +151,5 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline if (trackWasPlaying) adjustableClock.Start(); } - - protected override ScrollbarContainer CreateScrollbar(Direction direction) => new TimelineScrollbar(this, direction); - - private class TimelineScrollbar : ScrollbarContainer - { - private readonly Timeline timeline; - - public TimelineScrollbar(Timeline timeline, Direction scrollDir) - : base(scrollDir) - { - this.timeline = timeline; - } - - protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) - { - if (base.OnMouseDown(state, args)) - { - timeline.beginUserDrag(); - return true; - } - - return false; - } - - protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) - { - timeline.endUserDrag(); - return base.OnMouseUp(state, args); - } - } } } From 34f23359bb773c8997e8e34a1e65d31374e679d9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 16:20:31 +0900 Subject: [PATCH 087/186] Fix unit tests --- .../Visual/TestCaseZoomableScrollContainer.cs | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 70dd67cdbd..0d6526b637 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -77,16 +77,12 @@ namespace osu.Game.Tests.Visual // Scroll in at 0.25 AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by 3", () => InputManager.ScrollBy(new Vector2(3, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by 3", () => InputManager.ScrollBy(new Vector2(0, 3))); AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X)); // Scroll out at 0.25 - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by -3", () => InputManager.ScrollBy(new Vector2(-3, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by -3", () => InputManager.ScrollBy(new Vector2(0, -3))); AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); AddAssert("Box 1/4 at 1/4", () => Precision.AlmostEquals(boxQuad.TopLeft.X + 0.25f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X)); } @@ -98,15 +94,11 @@ namespace osu.Game.Tests.Visual // Scroll in at 0.25 AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(0, 1))); // Scroll in at 0.6 AddStep("Move mouse to 0.75x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.75f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by 1", () => InputManager.ScrollBy(new Vector2(0, 1))); AddAssert("Box not at 0", () => !Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); // Very hard to determine actual position, so approximate @@ -115,15 +107,11 @@ namespace osu.Game.Tests.Visual AddAssert("Box at correct position (3)", () => Precision.DefinitelyBigger(boxQuad.TopLeft.X + 0.6f * boxQuad.Size.X, scrollQuad.TopLeft.X + 0.6f * scrollQuad.Size.X)); // Scroll out at 0.6 - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(-1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(0, -1))); // Scroll out at 0.25 AddStep("Move mouse to 0.25x", () => InputManager.MoveMouseTo(new Vector2(scrollQuad.TopLeft.X + 0.25f * scrollQuad.Size.X, scrollQuad.Centre.Y))); - AddStep("Press ctrl", () => InputManager.PressKey(Key.LControl)); - AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(-1, 0))); - AddStep("Release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + AddStep("Scroll by -1", () => InputManager.ScrollBy(new Vector2(0, -1))); AddAssert("Box at 0", () => Precision.AlmostEquals(boxQuad.TopLeft, scrollQuad.TopLeft)); } From 93d2b5c4dea32f93186e877697cb95cf806e902b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 16:20:38 +0900 Subject: [PATCH 088/186] Adjust precision for failing test --- osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 0d6526b637..7fe59979a1 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual { reset(); AddStep("Set zoom = 10", () => scrollContainer.Zoom = 10); - AddAssert("Box at 1/2", () => Precision.AlmostEquals(boxQuad.Centre, scrollQuad.Centre)); + AddAssert("Box at 1/2", () => Precision.AlmostEquals(boxQuad.Centre, scrollQuad.Centre, 1)); AddAssert("Box width = 10x", () => Precision.AlmostEquals(boxQuad.Size.X, 10 * scrollQuad.Size.X)); } From ac1990c093a9f69eabdbe49af90182794466ee3c Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Tue, 12 Jun 2018 16:36:46 +0900 Subject: [PATCH 089/186] Remove unused using --- osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 7fe59979a1..8bd1b79a84 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics.Cursor; using osu.Game.Screens.Edit.Screens.Compose.Timeline; using OpenTK; using OpenTK.Graphics; -using OpenTK.Input; namespace osu.Game.Tests.Visual { From c70c7a476bf492d6f157fabc36406093bf0eafc3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 17:59:59 +0900 Subject: [PATCH 090/186] Always display the key counter during replay/autoplay --- osu.Game/Screens/Play/KeyCounterCollection.cs | 12 ++++++++---- osu.Game/Screens/Play/Player.cs | 13 +++++++------ osu.Game/Screens/Play/ReplayPlayer.cs | 7 +++++++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index 8cbb9986e5..8b579f41ac 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -18,7 +18,8 @@ namespace osu.Game.Screens.Play { private const int duration = 100; - private Bindable showKeyCounter; + public readonly Bindable Visible = new Bindable(true); + private readonly Bindable alwaysVisible = new Bindable(); public KeyCounterCollection() { @@ -46,9 +47,10 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - showKeyCounter = config.GetBindable(OsuSetting.KeyOverlay); - showKeyCounter.ValueChanged += keyCounterVisibility => this.FadeTo(keyCounterVisibility ? 1 : 0, duration); - showKeyCounter.TriggerChange(); + config.BindWith(OsuSetting.KeyOverlay, alwaysVisible); + + Visible.BindValueChanged(_ => updateVisibility()); + alwaysVisible.BindValueChanged(_ => updateVisibility(), true); } //further: change default values here and in KeyCounter if needed, instead of passing them in every constructor @@ -111,6 +113,8 @@ namespace osu.Game.Screens.Play } } + private void updateVisibility() => this.FadeTo(Visible.Value || alwaysVisible.Value ? 1 : 0, duration); + public override bool HandleKeyboardInput => receptor == null; public override bool HandleMouseInput => receptor == null; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 04148cd558..5fd85ce6e7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play protected ScoreProcessor ScoreProcessor; protected RulesetContainer RulesetContainer; - private HUDOverlay hudOverlay; + protected HUDOverlay HudOverlay; private FailOverlay failOverlay; private DrawableStoryboard storyboard; @@ -170,9 +170,9 @@ namespace osu.Game.Screens.Play OnPause = () => { pauseContainer.Retries = RestartCount; - hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; + HudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, - OnResume = () => hudOverlay.KeyCounter.IsCounting = true, + OnResume = () => HudOverlay.KeyCounter.IsCounting = true, Children = new[] { storyboardContainer = new Container @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Play Breaks = beatmap.Breaks }, RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) + HudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { Clock = Clock, // hud overlay doesn't want to use the audio clock directly ProcessCustomClock = false, @@ -228,7 +228,8 @@ namespace osu.Game.Screens.Play } }; - hudOverlay.HoldToQuit.Action = Exit; + HudOverlay.HoldToQuit.Action = Exit; + HudOverlay.KeyCounter.Visible.Value = RulesetContainer.HasReplayLoaded; if (ShowStoryboard) initializeStoryboard(false); @@ -368,7 +369,7 @@ namespace osu.Game.Screens.Play RulesetContainer?.FadeOut(fade_out_duration); Content.FadeOut(fade_out_duration); - hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); + HudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); Background?.FadeTo(1f, fade_out_duration); } diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 6e2a2e4c9c..16f8a4b361 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Framework.Allocation; using osu.Game.Rulesets.Replays; namespace osu.Game.Screens.Play @@ -14,6 +15,12 @@ namespace osu.Game.Screens.Play Replay = replay; } + [BackgroundDependencyLoader] + private void load() + { + HudOverlay.KeyCounter.Visible.Value = true; + } + protected override void LoadComplete() { base.LoadComplete(); From bcfb092e53709f65391d6c7294b0f3c2762c4c2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 12 Jun 2018 18:03:45 +0900 Subject: [PATCH 091/186] Change step to 200 --- osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 231892bdd9..830214803c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// The step increase/decrease of the span of time visible by the length of the scrolling axes. /// - private const double time_span_step = 500; + private const double time_span_step = 200; /// /// The span of time that is visible by the length of the scrolling axes. From 67aa52fb1d79851e1049eea82f6bc4a942dd040f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 19:34:49 +0900 Subject: [PATCH 092/186] Use bindable binding --- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/ReplayPlayer.cs | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5fd85ce6e7..7e0321d81d 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -229,7 +229,7 @@ namespace osu.Game.Screens.Play }; HudOverlay.HoldToQuit.Action = Exit; - HudOverlay.KeyCounter.Visible.Value = RulesetContainer.HasReplayLoaded; + HudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); if (ShowStoryboard) initializeStoryboard(false); diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 16f8a4b361..6e2a2e4c9c 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Allocation; using osu.Game.Rulesets.Replays; namespace osu.Game.Screens.Play @@ -15,12 +14,6 @@ namespace osu.Game.Screens.Play Replay = replay; } - [BackgroundDependencyLoader] - private void load() - { - HudOverlay.KeyCounter.Visible.Value = true; - } - protected override void LoadComplete() { base.LoadComplete(); From ca3186f34c7b2507fef6e0900e61e5c7e9746c82 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 12 Jun 2018 19:51:35 +0900 Subject: [PATCH 093/186] Create dependencies before children are loaded --- osu.Game/Tests/Visual/EditorClockTestCase.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/EditorClockTestCase.cs b/osu.Game/Tests/Visual/EditorClockTestCase.cs index 08dc6a3bbd..521b51529e 100644 --- a/osu.Game/Tests/Visual/EditorClockTestCase.cs +++ b/osu.Game/Tests/Visual/EditorClockTestCase.cs @@ -25,13 +25,20 @@ namespace osu.Game.Tests.Visual Clock = new EditorClock(new ControlPointInfo(), 5000, BeatDivisor) { IsCoupled = false }; } + protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent)); + + dependencies.Cache(BeatDivisor); + dependencies.CacheAs(Clock); + dependencies.CacheAs(Clock); + + return dependencies; + } + [BackgroundDependencyLoader] private void load() { - Dependencies.Cache(BeatDivisor); - Dependencies.CacheAs(Clock); - Dependencies.CacheAs(Clock); - Beatmap.BindValueChanged(beatmapChanged, true); } From 2a5a52422320cbe39cbcf03614919528c92da78f Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Tue, 12 Jun 2018 20:37:01 +0200 Subject: [PATCH 094/186] delete COMPILING.md --- COMPILING.md | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 COMPILING.md diff --git a/COMPILING.md b/COMPILING.md deleted file mode 100644 index bfcbf6bc2c..0000000000 --- a/COMPILING.md +++ /dev/null @@ -1,36 +0,0 @@ -# Linux -### 1. Requirements: -Mono >= 5.4.0 (>= 5.8.0 recommended) -Please check [here](http://www.mono-project.com/download/) for stable or [here](http://www.mono-project.com/download/alpha/) for an alpha release. -NuGet >= 4.4.0 -msbuild -git - -### 2. Cloning project -Clone the entire repository with submodules using -``` -git clone https://github.com/ppy/osu --recursive -``` -Then restore NuGet packages from the repository -``` -nuget restore -``` -### 3. Compiling -Simply run `msbuild` where `osu.sln` is located, this will create all binaries in `osu/osu.Desktop/bin/Debug`. -### 4. Optimizing -If you want additional performance you can change build type to Release with -``` -msbuild -p:Configuration=Release -``` -Additionally, mono provides an AOT utility which attempts to precompile binaries. You can utilize that by running -``` -mono --aot ./osu\!.exe -``` -### 5. Troubleshooting -You may run into trouble with NuGet versioning, as the one in packaging system is almost always out of date. Simply run -``` -nuget -sudo nuget update -self -``` -**Warning** NuGet creates few config files when it's run for the first time. -Do not run NuGet as root on the first run or you might run into very peculiar issues. From d9e7a324c0c892a1299bdd7764978b9c7596a792 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 11:30:22 +0900 Subject: [PATCH 095/186] Revert HudOverlay to private field --- osu.Game/Screens/Play/Player.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7e0321d81d..a2ed01f5a7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play protected ScoreProcessor ScoreProcessor; protected RulesetContainer RulesetContainer; - protected HUDOverlay HudOverlay; + private HUDOverlay hudOverlay; private FailOverlay failOverlay; private DrawableStoryboard storyboard; @@ -170,9 +170,9 @@ namespace osu.Game.Screens.Play OnPause = () => { pauseContainer.Retries = RestartCount; - HudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; + hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused; }, - OnResume = () => HudOverlay.KeyCounter.IsCounting = true, + OnResume = () => hudOverlay.KeyCounter.IsCounting = true, Children = new[] { storyboardContainer = new Container @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Play Breaks = beatmap.Breaks }, RulesetContainer.Cursor?.CreateProxy() ?? new Container(), - HudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) + hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock) { Clock = Clock, // hud overlay doesn't want to use the audio clock directly ProcessCustomClock = false, @@ -228,8 +228,8 @@ namespace osu.Game.Screens.Play } }; - HudOverlay.HoldToQuit.Action = Exit; - HudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); + hudOverlay.HoldToQuit.Action = Exit; + hudOverlay.KeyCounter.Visible.BindTo(RulesetContainer.HasReplayLoaded); if (ShowStoryboard) initializeStoryboard(false); @@ -369,7 +369,7 @@ namespace osu.Game.Screens.Play RulesetContainer?.FadeOut(fade_out_duration); Content.FadeOut(fade_out_duration); - HudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); + hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In); Background?.FadeTo(1f, fade_out_duration); } From a7ed3ea80b59f5d09143094eae2036f74c1c4d8c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 11:38:15 +0900 Subject: [PATCH 096/186] Rename alwaysVisible to explain where it comes from --- osu.Game/Screens/Play/KeyCounterCollection.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounterCollection.cs b/osu.Game/Screens/Play/KeyCounterCollection.cs index 8b579f41ac..114ea83ba6 100644 --- a/osu.Game/Screens/Play/KeyCounterCollection.cs +++ b/osu.Game/Screens/Play/KeyCounterCollection.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Play private const int duration = 100; public readonly Bindable Visible = new Bindable(true); - private readonly Bindable alwaysVisible = new Bindable(); + private readonly Bindable configVisibility = new Bindable(); public KeyCounterCollection() { @@ -47,10 +47,10 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - config.BindWith(OsuSetting.KeyOverlay, alwaysVisible); + config.BindWith(OsuSetting.KeyOverlay, configVisibility); Visible.BindValueChanged(_ => updateVisibility()); - alwaysVisible.BindValueChanged(_ => updateVisibility(), true); + configVisibility.BindValueChanged(_ => updateVisibility(), true); } //further: change default values here and in KeyCounter if needed, instead of passing them in every constructor @@ -113,7 +113,7 @@ namespace osu.Game.Screens.Play } } - private void updateVisibility() => this.FadeTo(Visible.Value || alwaysVisible.Value ? 1 : 0, duration); + private void updateVisibility() => this.FadeTo(Visible.Value || configVisibility.Value ? 1 : 0, duration); public override bool HandleKeyboardInput => receptor == null; public override bool HandleMouseInput => receptor == null; From b182635aae9b160bdc77775a7cea0d4203d56548 Mon Sep 17 00:00:00 2001 From: Joehu Date: Tue, 12 Jun 2018 20:21:37 -0700 Subject: [PATCH 097/186] Fix taiko nightcore regression --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index ccf28a2f12..225461fd6f 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Taiko { new TaikoModHardRock(), new MultiMod(new TaikoModSuddenDeath(), new TaikoModPerfect()), - new MultiMod(new TaikoModDoubleTime(), new TaikoModDaycore()), + new MultiMod(new TaikoModDoubleTime(), new TaikoModNightcore()), new TaikoModHidden(), new TaikoModFlashlight(), }; From f4cb0d7d8daf7abd57ec9d50daae1e6d8fba5d74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 14:16:58 +0900 Subject: [PATCH 098/186] Fix memory leak due to incorrect binding --- osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs index 240d8dc396..35146dfe29 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; this.beatmap.BindTo(beatmap); - beatmap.ValueChanged += v => calculateScale(); + this.beatmap.ValueChanged += v => calculateScale(); cursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); cursorScale.ValueChanged += v => calculateScale(); From 14f5c814a69b66237840ede64c389f99c56409c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:12:10 +0900 Subject: [PATCH 099/186] Add test for WorkingBeatmap leakage --- osu.Game/Tests/Visual/TestCasePlayer.cs | 34 ++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 3cdc496ee1..55fb9c483b 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -1,9 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; +using osu.Framework.Lists; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -43,6 +46,7 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => ContinueCondition(p)); + } else { @@ -51,6 +55,20 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(r.Name, () => p = loadPlayerFor(r)); AddUntilStep(() => ContinueCondition(p)); + AddAssert("no leaked beatmaps", () => + { + p = null; + + GC.Collect(); + GC.WaitForPendingFinalizers(); + int count = 0; + + workingWeakReferences.ForEachAlive(_ => count++); + + Logger.Log($"reference count {count}"); + + return count == 1; + }); } } } @@ -59,21 +77,29 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); + private readonly WeakList workingWeakReferences = new WeakList(); + private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); private Player loadPlayerFor(Ruleset r) { var beatmap = CreateBeatmap(r); + var working = new TestWorkingBeatmap(beatmap); - Beatmap.Value = new TestWorkingBeatmap(beatmap); + workingWeakReferences.Add(working); + + Beatmap.Value = working; Beatmap.Value.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; - if (Player != null) - Remove(Player); + Player?.Exit(); var player = CreatePlayer(r); - LoadComponentAsync(player, LoadScreen); + LoadComponentAsync(player, p => + { + Player = p; + LoadScreen(p); + }); return player; } From 39738a997eab5c7a085c44633883c9bbab155b9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:26:05 +0900 Subject: [PATCH 100/186] Add check for player screens too --- osu.Game/Tests/Visual/TestCasePlayer.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 55fb9c483b..beaa6bb43a 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Framework.Lists; -using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -55,6 +54,7 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(r.Name, () => p = loadPlayerFor(r)); AddUntilStep(() => ContinueCondition(p)); + AddAssert("no leaked beatmaps", () => { p = null; @@ -64,9 +64,16 @@ namespace osu.Game.Tests.Visual int count = 0; workingWeakReferences.ForEachAlive(_ => count++); + return count == 1; + }); - Logger.Log($"reference count {count}"); + AddAssert("no leaked players", () => + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + int count = 0; + playerWeakReferences.ForEachAlive(_ => count++); return count == 1; }); } @@ -78,6 +85,7 @@ namespace osu.Game.Tests.Visual protected virtual IBeatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); private readonly WeakList workingWeakReferences = new WeakList(); + private readonly WeakList playerWeakReferences = new WeakList(); private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); @@ -95,6 +103,8 @@ namespace osu.Game.Tests.Visual var player = CreatePlayer(r); + playerWeakReferences.Add(player); + LoadComponentAsync(player, p => { Player = p; From 0fdb04f57dcbba6077f8e04020bed92e6678aa08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 15:43:00 +0900 Subject: [PATCH 101/186] Fix empty line --- osu.Game/Tests/Visual/TestCasePlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index beaa6bb43a..20c9646aa3 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -45,7 +45,6 @@ namespace osu.Game.Tests.Visual Player p = null; AddStep(ruleset.RulesetInfo.Name, () => p = loadPlayerFor(ruleset)); AddUntilStep(() => ContinueCondition(p)); - } else { From 2a18625b2c95f2f2fda8981365f177417e339969 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 16:46:27 +0900 Subject: [PATCH 102/186] Correctly block scroll events when hovering controls --- osu.Game/Overlays/Volume/VolumeMeter.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 451809867d..29fef48d13 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -177,12 +177,13 @@ namespace osu.Game.Overlays.Volume { float amount = adjust_step * direction; - var mouse = GetContainingInputManager().CurrentState.Mouse; - if (mouse.HasPreciseScroll) + // handle the case where the OnPressed action was actually a mouse wheel. + // this allows for precise wheel handling. + var state = GetContainingInputManager().CurrentState; + if (state.Mouse?.ScrollDelta.Y != 0) { - float scrollDelta = mouse.ScrollDelta.Y; - if (scrollDelta != 0) - amount *= Math.Abs(scrollDelta / 10); + OnScroll(state); + return; } Volume += amount; @@ -205,6 +206,14 @@ namespace osu.Game.Overlays.Volume return false; } + protected override bool OnScroll(InputState state) + { + double amount = adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.5f : 1); + + Volume += Math.Sign(amount) * Math.Max(0.01, Math.Abs(amount)); + return true; + } + public bool OnReleased(GlobalAction action) => false; private const float transition_length = 500; From a55bf82fd9c4c76f269fb08fd2dbd4697194c9e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 16:46:48 +0900 Subject: [PATCH 103/186] Handle hover blocking in VolumeOverlay to ensure correct hide scheduling --- osu.Game/Overlays/Volume/VolumeMeter.cs | 2 +- osu.Game/Overlays/VolumeOverlay.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 29fef48d13..b3dd06022e 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -221,7 +221,7 @@ namespace osu.Game.Overlays.Volume protected override bool OnHover(InputState state) { this.ScaleTo(1.04f, transition_length, Easing.OutExpo); - return true; + return false; } protected override void OnHoverLost(InputState state) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 5a3d51c00a..a56a160e20 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -142,13 +142,18 @@ namespace osu.Game.Overlays return base.OnMouseMove(state); } + protected override bool OnHover(InputState state) + { + Show(); + return true; + } + private void schedulePopOut() { popOutDelegate?.Cancel(); this.Delay(1000).Schedule(() => { - // only actually hide if the mouse isn't within our bounds. - if (!ScreenSpaceDrawQuad.Contains(GetContainingInputManager().CurrentState.Mouse.Position)) + if (!IsHovered) Hide(); }, out popOutDelegate); } From e0b68e4e09c0838c93e3c96746b284c5110314c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 16:47:10 +0900 Subject: [PATCH 104/186] Fix hide re-schedule not triggering on noop state change --- osu.Game/Overlays/VolumeOverlay.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index a56a160e20..24afa414d6 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -122,6 +122,14 @@ namespace osu.Game.Overlays private ScheduledDelegate popOutDelegate; + public override void Show() + { + if (State == Visibility.Visible) + schedulePopOut(); + + base.Show(); + } + protected override void PopIn() { ClearTransforms(); From cee5be1d56028f9c0858a6923583ba5ed8ce9e2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 17:03:56 +0900 Subject: [PATCH 105/186] Improve precision wheel adjustment handling --- osu.Game/Overlays/Volume/VolumeMeter.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index b3dd06022e..4d20166784 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -206,11 +206,18 @@ namespace osu.Game.Overlays.Volume return false; } + // because volume precision is set to 0.01, this local is required to keep track of more precise adjustments and only apply when possible. + private double scrollAmount; + protected override bool OnScroll(InputState state) { - double amount = adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.5f : 1); + scrollAmount += adjust_step * state.Mouse.ScrollDelta.Y * (state.Mouse.HasPreciseScroll ? 0.1f : 1); - Volume += Math.Sign(amount) * Math.Max(0.01, Math.Abs(amount)); + if (Math.Abs(scrollAmount) < Bindable.Precision) + return true; + + Volume += scrollAmount; + scrollAmount = 0; return true; } From b318b770d4ea82efdb6f24b11f1cf131af77d2bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 13 Jun 2018 19:18:11 +0900 Subject: [PATCH 106/186] Fix pixellation of volume meter progress bars --- osu.Game.Tests/Visual/TestCaseVolumePieces.cs | 13 +- osu.Game/Overlays/Volume/VolumeMeter.cs | 200 +++++++++++------- 2 files changed, 139 insertions(+), 74 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseVolumePieces.cs b/osu.Game.Tests/Visual/TestCaseVolumePieces.cs index 449f48b7d7..3c5b91ccd2 100644 --- a/osu.Game.Tests/Visual/TestCaseVolumePieces.cs +++ b/osu.Game.Tests/Visual/TestCaseVolumePieces.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Overlays.Volume; +using OpenTK; using OpenTK.Graphics; namespace osu.Game.Tests.Visual @@ -17,13 +18,21 @@ namespace osu.Game.Tests.Visual { VolumeMeter meter; MuteButton mute; - Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue)); + Add(meter = new VolumeMeter("MASTER", 125, Color4.Blue) { Position = new Vector2(10) }); + AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1); + + Add(new VolumeMeter("BIG", 250, Color4.Red) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Position = new Vector2(10), + }); + Add(mute = new MuteButton { Margin = new MarginPadding { Top = 200 } }); - AddSliderStep("master volume", 0, 10, 0, i => meter.Bindable.Value = i * 0.1); AddToggleStep("mute", b => mute.Current.Value = b); } } diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index b2cf43704b..0e43945f8c 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -24,6 +24,8 @@ namespace osu.Game.Overlays.Volume public class VolumeMeter : Container, IKeyBindingHandler { private CircularProgress volumeCircle; + private CircularProgress volumeCircleGlow; + public BindableDouble Bindable { get; } = new BindableDouble { MinValue = 0, MaxValue = 1 }; private readonly float circleSize; private readonly Color4 meterColour; @@ -44,90 +46,143 @@ namespace osu.Game.Overlays.Volume [BackgroundDependencyLoader] private void load(OsuColour colours) { - Add(new Container - { - Size = new Vector2(120, 20), - CornerRadius = 10, - Masking = true, - Margin = new MarginPadding { Left = circleSize + 10 }, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - Alpha = 0.9f, - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = "Exo2.0-Bold", - Text = name - } - } - }); + Color4 backgroundColour = colours.Gray1; CircularProgress bgProgress; - Add(new CircularContainer + const float progress_start_radius = 0.75f; + const float progress_size = 0.03f; + const float progress_end_radius = progress_start_radius + progress_size; + + const float blur_amount = 5; + + Children = new Drawable[] { - Masking = true, - Size = new Vector2(circleSize), - Children = new Drawable[] + new Container { - new Box + Size = new Vector2(circleSize), + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - Alpha = 0.9f, - }, - bgProgress = new CircularProgress - { - RelativeSizeAxes = Axes.Both, - InnerRadius = 0.05f, - Rotation = 180, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.Gray2, - Size = new Vector2(0.8f) - }, - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.8f), - Padding = new MarginPadding(-Blur.KernelSize(5)), - Rotation = 180, - Child = (volumeCircle = new CircularProgress + new BufferedContainer { + Alpha = 0.9f, RelativeSizeAxes = Axes.Both, - InnerRadius = 0.05f, + Children = new Drawable[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour, + }, + new CircularContainer + { + Masking = true, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(progress_end_radius), + Children = new Drawable[] + { + bgProgress = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Rotation = 180, + Colour = backgroundColour, + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Progress under covers for smoothing", + RelativeSizeAxes = Axes.Both, + Rotation = 180, + Child = volumeCircle = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + } + }, + } + }, + new Circle + { + Name = "Inner Cover", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour, + Size = new Vector2(progress_start_radius), + }, + new Container + { + Name = "Progress overlay for glow", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(progress_start_radius + progress_size / 1.5f), + Rotation = 180, + Padding = new MarginPadding(-Blur.KernelSize(blur_amount)), + Child = (volumeCircleGlow = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + InnerRadius = progress_size * 0.8f, + }).WithEffect(new GlowEffect + { + Colour = meterColour, + BlurSigma = new Vector2(blur_amount), + Strength = 5, + PadExtent = true + }), + }, + }, + }, + maxGlow = (text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = "Venera", + TextSize = 0.16f * circleSize }).WithEffect(new GlowEffect { - Colour = meterColour, - Strength = 2, - PadExtent = true - }), - }, - maxGlow = (text = new OsuSpriteText + Colour = Color4.Transparent, + PadExtent = true, + }) + } + }, + new Container + { + Size = new Vector2(120, 20), + CornerRadius = 10, + Masking = true, + Margin = new MarginPadding { Left = circleSize + 10 }, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = "Venera", - TextSize = 0.16f * circleSize - }).WithEffect(new GlowEffect - { - Colour = Color4.Transparent, - PadExtent = true, - }) + new Box + { + Alpha = 0.9f, + RelativeSizeAxes = Axes.Both, + Colour = backgroundColour, + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = "Exo2.0-Bold", + Text = name + } + } } - }); - - Bindable.ValueChanged += newVolume => { this.TransformTo("DisplayVolume", newVolume, 400, Easing.OutQuint); }; + }; + Bindable.ValueChanged += newVolume => + { + this.TransformTo("DisplayVolume", + newVolume, + 400, + Easing.OutQuint); + }; bgProgress.Current.Value = 0.75f; } @@ -158,6 +213,7 @@ namespace osu.Game.Overlays.Volume } volumeCircle.Current.Value = displayVolume * 0.75f; + volumeCircleGlow.Current.Value = displayVolume * 0.75f; } } From 1431ee1867f6f4ca4f648158a316853f3c580d16 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 14:46:25 +0900 Subject: [PATCH 107/186] Remove unused method --- osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 31cd9dc6f5..a9bf5b1797 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -33,10 +33,6 @@ namespace osu.Game.Rulesets.Difficulty TimeRate = clock.Rate; } - protected virtual void PreprocessHitObjects() - { - } - /// /// Creates all combinations which adjust the difficulty. /// From b7a06b95944fdde0083c7f3f14bfed2132bcc074 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:32:07 +0900 Subject: [PATCH 108/186] Restructure of DifficultyCalculator to cleanup mod + attribute handling --- .../Difficulty/DifficultyAttributes.cs | 19 +++++++ .../Difficulty/DifficultyCalculator.cs | 51 ++++++++++++++----- osu.Game/Rulesets/Ruleset.cs | 2 +- 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs new file mode 100644 index 0000000000..1fdebd586f --- /dev/null +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Difficulty +{ + public class DifficultyAttributes + { + public readonly Mod[] Mods; + public readonly double StarRating; + + public DifficultyAttributes(Mod[] mods, double starRating) + { + Mods = mods; + StarRating = starRating; + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index a9bf5b1797..8f9651ab09 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -13,24 +13,44 @@ namespace osu.Game.Rulesets.Difficulty { public abstract class DifficultyCalculator { - protected readonly IBeatmap Beatmap; - protected readonly Mod[] Mods; + private readonly Ruleset ruleset; + private readonly WorkingBeatmap beatmap; - protected double TimeRate { get; private set; } = 1; - - protected DifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) + protected DifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) { - Beatmap = beatmap; - Mods = mods ?? new Mod[0]; - - ApplyMods(Mods); + this.ruleset = ruleset; + this.beatmap = beatmap; } - protected virtual void ApplyMods(Mod[] mods) + /// + /// Calculates the difficulty of the beatmap using a specific mod combination. + /// + /// The mods that should be applied to the beatmap. + /// A structure describing the difficulty of the beatmap. + public DifficultyAttributes Calculate(params Mod[] mods) { + beatmap.Mods.Value = mods; + IBeatmap playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo); + var clock = new StopwatchClock(); mods.OfType().ForEach(m => m.ApplyToClock(clock)); - TimeRate = clock.Rate; + + return Calculate(playableBeatmap, mods, clock.Rate); + } + + /// + /// Calculates the difficulty of the beatmap using all mod combinations applicable to the beatmap. + /// + /// A collection of structures describing the difficulty of the beatmap for each mod combination. + public IEnumerable CalculateAll() + { + foreach (var combination in CreateDifficultyAdjustmentModCombinations()) + { + if (combination is MultiMod multi) + yield return Calculate(multi.Mods); + else + yield return Calculate(combination); + } } /// @@ -71,6 +91,13 @@ namespace osu.Game.Rulesets.Difficulty /// protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty(); - public abstract double Calculate(Dictionary categoryDifficulty = null); + /// + /// Calculates the difficulty of a using a specific combination. + /// + /// The to compute the difficulty for. + /// The s that should be applied. + /// The rate of time in . + /// A structure containing the difficulty attributes. + protected abstract DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index a39e8bb8d4..cdc1c44306 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null; - public abstract DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null); + public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap); public virtual PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => null; From 47fc18d7c48bc7e5b5f4dce262fc76ee28626372 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:36:49 +0900 Subject: [PATCH 109/186] Adjust OsuDifficultyCalculator in-line with changes --- .../Difficulty/OsuDifficultyAttributes.cs | 19 ++++++++++++ .../Difficulty/OsuDifficultyCalculator.cs | 30 +++++++------------ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- 3 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs new file mode 100644 index 0000000000..5650bc395a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -0,0 +1,19 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Osu.Difficulty +{ + public class OsuDifficultyAttributes : DifficultyAttributes + { + public double AimStrain { get; set; } + public double SpeedStrain { get; set; } + + public OsuDifficultyAttributes(Mod[] mods, double starRating) + : base(mods, starRating) + { + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 94d2afbf45..400afbc043 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -2,7 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -18,31 +18,26 @@ namespace osu.Game.Rulesets.Osu.Difficulty private const int section_length = 400; private const double difficulty_multiplier = 0.0675; - public OsuDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public OsuDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public OsuDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } - - public override double Calculate(Dictionary categoryDifficulty = null) - { - OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap((List)Beatmap.HitObjects, TimeRate); + OsuDifficultyBeatmap difficultyBeatmap = new OsuDifficultyBeatmap(beatmap.HitObjects.Cast().ToList(), timeRate); Skill[] skills = { new Aim(), new Speed() }; - double sectionLength = section_length * TimeRate; + double sectionLength = section_length * timeRate; // The first object doesn't generate a strain, so we begin with an incremented section end double currentSectionEnd = 2 * sectionLength; - foreach (OsuDifficultyHitObject h in beatmap) + foreach (OsuDifficultyHitObject h in difficultyBeatmap) { while (h.BaseObject.StartTime > currentSectionEnd) { @@ -61,16 +56,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; - double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; - if (categoryDifficulty != null) + return new OsuDifficultyAttributes(mods, starRating) { - categoryDifficulty.Add("Aim", aimRating); - categoryDifficulty.Add("Speed", speedRating); - } - - return starRating; + AimStrain = aimRating, + SpeedStrain = speedRating + }; } protected override Mod[] DifficultyAdjustmentMods => new Mod[] diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6ab75d008f..49468392f5 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap); public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); From 33c7ce1bec1a51a70b9a2da9629ef3182132bc32 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:47:42 +0900 Subject: [PATCH 110/186] Adjust TaikoDifficultyCalculator in-line with changes --- .../Difficulty/TaikoDifficultyCalculator.cs | 59 ++++++++----------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index bb666eb528..473c205293 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -27,54 +27,33 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// private const double decay_weight = 0.9; - /// - /// HitObjects are stored as a member variable. - /// - private readonly List difficultyHitObjects = new List(); - - public TaikoDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public TaikoDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public TaikoDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } + var difficultyHitObjects = new List(); - public override double Calculate(Dictionary categoryDifficulty = null) - { - // Fill our custom DifficultyHitObject class, that carries additional information - difficultyHitObjects.Clear(); - - foreach (var hitObject in Beatmap.HitObjects) + foreach (var hitObject in beatmap.HitObjects) difficultyHitObjects.Add(new TaikoHitObjectDifficulty((TaikoHitObject)hitObject)); // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime)); - if (!calculateStrainValues()) return 0; + if (!calculateStrainValues(difficultyHitObjects, timeRate)) + return new DifficultyAttributes(mods, 0); - double starRating = calculateDifficulty() * star_scaling_factor; + double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; - if (categoryDifficulty != null) - categoryDifficulty["Strain"] = starRating; - - return starRating; + return new DifficultyAttributes(mods, starRating); } - protected override Mod[] DifficultyAdjustmentMods => new Mod[] - { - new TaikoModDoubleTime(), - new TaikoModHalfTime(), - new TaikoModEasy(), - new TaikoModHardRock(), - }; - - private bool calculateStrainValues() + private bool calculateStrainValues(List objects, double timeRate) { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. - using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + using (var hitObjectsEnumerator = objects.GetEnumerator()) { if (!hitObjectsEnumerator.MoveNext()) return false; @@ -84,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty while (hitObjectsEnumerator.MoveNext()) { var next = hitObjectsEnumerator.Current; - next?.CalculateStrains(current, TimeRate); + next?.CalculateStrains(current, timeRate); current = next; } @@ -92,9 +71,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty } } - private double calculateDifficulty() + private double calculateDifficulty(List objects, double timeRate) { - double actualStrainStep = strain_step * TimeRate; + double actualStrainStep = strain_step * timeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -102,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval TaikoHitObjectDifficulty previousHitObject = null; - foreach (var hitObject in difficultyHitObjects) + foreach (var hitObject in objects) { // While we are beyond the current interval push the currently available maximum to our strain list while (hitObject.BaseHitObject.StartTime > intervalEndTime) @@ -144,5 +123,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return difficulty; } + + protected override Mod[] DifficultyAdjustmentMods => new Mod[] + { + new TaikoModDoubleTime(), + new TaikoModHalfTime(), + new TaikoModEasy(), + new TaikoModHardRock(), + }; } } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 225461fd6f..1b34ab68bd 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap, mods); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap); public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); From 6ff06d4757f4bb00f94bb7870235b4b18bd9b920 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:48:56 +0900 Subject: [PATCH 111/186] Adjust CatchDifficultyCalculator in-line with changes --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../Difficulty/CatchDifficultyCalculator.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index d0180f1791..fc6e23c884 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Catch public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap); public override int? LegacyID => 2; diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index f8351b7519..562374087e 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -1,18 +1,19 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Catch.Difficulty { public class CatchDifficultyCalculator : DifficultyCalculator { - public CatchDifficultyCalculator(IBeatmap beatmap) : base(beatmap) + public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => new DifficultyAttributes(mods, 0); } } From 966099fabc209b34f2ac2bcc7881b0639eb465f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:54:05 +0900 Subject: [PATCH 112/186] Adjust ManiaDifficultyCalculator in-line with changes --- .../Difficulty/ManiaDifficultyCalculator.cs | 47 +++++++------------ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index ca2002b7c9..9c091ac31a 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -29,47 +29,33 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// private const double decay_weight = 0.9; - /// - /// HitObjects are stored as a member variable. - /// - private readonly List difficultyHitObjects = new List(); - - public ManiaDifficultyCalculator(IBeatmap beatmap) - : base(beatmap) + public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) + : base(ruleset, beatmap) { } - public ManiaDifficultyCalculator(IBeatmap beatmap, Mod[] mods) - : base(beatmap, mods) + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) { - } + var difficultyHitObjects = new List(); - public override double Calculate(Dictionary categoryDifficulty = null) - { - // Fill our custom DifficultyHitObject class, that carries additional information - difficultyHitObjects.Clear(); - - int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7; + int columnCount = ((ManiaBeatmap)beatmap).TotalColumns; // Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure. // Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change - difficultyHitObjects.AddRange(Beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime)); + difficultyHitObjects.AddRange(beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime)); - if (!calculateStrainValues()) - return 0; + if (!calculateStrainValues(difficultyHitObjects, timeRate)) + return new DifficultyAttributes(mods, 0); - double starRating = calculateDifficulty() * star_scaling_factor; + double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor; - if (categoryDifficulty != null) - categoryDifficulty["Strain"] = starRating; - - return starRating; + return new DifficultyAttributes(mods, starRating); } - private bool calculateStrainValues() + private bool calculateStrainValues(List objects, double timeRate) { // Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment. - using (List.Enumerator hitObjectsEnumerator = difficultyHitObjects.GetEnumerator()) + using (var hitObjectsEnumerator = objects.GetEnumerator()) { if (!hitObjectsEnumerator.MoveNext()) return false; @@ -80,7 +66,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty while (hitObjectsEnumerator.MoveNext()) { var next = hitObjectsEnumerator.Current; - next?.CalculateStrains(current, TimeRate); + next?.CalculateStrains(current, timeRate); current = next; } @@ -88,9 +74,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty } } - private double calculateDifficulty() + private double calculateDifficulty(List objects, double timeRate) { - double actualStrainStep = strain_step * TimeRate; + double actualStrainStep = strain_step * timeRate; // Find the highest strain value within each strain step List highestStrains = new List(); @@ -98,7 +84,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval ManiaHitObjectDifficulty previousHitObject = null; - foreach (var hitObject in difficultyHitObjects) + foreach (var hitObject in objects) { // While we are beyond the current interval push the currently available maximum to our strain list while (hitObject.BaseHitObject.StartTime > intervalEndTime) @@ -159,5 +145,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty new ManiaModKey8(), new ManiaModKey9(), }; + } } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index e671a3fb14..1b7a8f77b3 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Mania public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods); + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap); public override int? LegacyID => 3; From 540b43313eba0932a1be122c2469d586409b3d1c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 15:57:06 +0900 Subject: [PATCH 113/186] Remove PP test cases (osu-tools/osu-server should be used instead) --- .../TestCasePerformancePoints.cs | 16 - .../TestCasePerformancePoints.cs | 16 - .../TestCasePerformancePoints.cs | 16 - .../TestCasePerformancePoints.cs | 16 - .../Tests/Visual/TestCasePerformancePoints.cs | 403 ------------------ 5 files changed, 467 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs delete mode 100644 osu.Game/Tests/Visual/TestCasePerformancePoints.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index 9512cf2061..0000000000 --- a/osu.Game.Rulesets.Catch.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Catch.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new CatchRuleset()) - { - } - } -} diff --git a/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index c15a6dd688..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Mania.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new ManiaRuleset()) - { - } - } -} diff --git a/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index 63026fe316..0000000000 --- a/osu.Game.Rulesets.Osu.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Osu.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new OsuRuleset()) - { - } - } -} diff --git a/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs b/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs deleted file mode 100644 index 2fd9161d13..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/TestCasePerformancePoints.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using NUnit.Framework; - -namespace osu.Game.Rulesets.Taiko.Tests -{ - [TestFixture] - public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints - { - public TestCasePerformancePoints() - : base(new TaikoRuleset()) - { - } - } -} diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs deleted file mode 100644 index dfae8fbc1d..0000000000 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using System.Linq; -using OpenTK; -using OpenTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Caching; -using osu.Framework.Configuration; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; -using osu.Game.Beatmaps; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Tests.Visual -{ - public abstract class TestCasePerformancePoints : OsuTestCase - { - protected TestCasePerformancePoints(Ruleset ruleset) - { - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new BeatmapList(ruleset, Beatmap) - } - } - }, - null, - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new StarRatingGrid() - } - } - }, - null, - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, - }, - new ScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = new PerformanceList() - } - } - }, - } - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 20), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 20) - } - }; - } - - private class BeatmapList : CompositeDrawable - { - private readonly Container beatmapDisplays; - private readonly Ruleset ruleset; - private readonly BindableBeatmap beatmapBindable; - - public BeatmapList(Ruleset ruleset, BindableBeatmap beatmapBindable) - { - this.ruleset = ruleset; - this.beatmapBindable = beatmapBindable; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = beatmapDisplays = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4) - }; - } - - [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) - { - var sets = beatmaps.GetAllUsableBeatmapSets(); - var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID); - - allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b, beatmapBindable))); - } - - private class BeatmapDisplay : CompositeDrawable, IHasTooltip - { - private readonly OsuSpriteText text; - private readonly BeatmapInfo beatmap; - - private readonly BindableBeatmap beatmapBindable; - - private BeatmapManager beatmaps; - - private bool isSelected; - - public string TooltipText => text.Text; - - public BeatmapDisplay(BeatmapInfo beatmap, BindableBeatmap beatmapBindable) - { - this.beatmap = beatmap; - this.beatmapBindable = beatmapBindable; - - AutoSizeAxes = Axes.Both; - InternalChild = text = new OsuSpriteText(); - - this.beatmapBindable.ValueChanged += beatmapChanged; - } - - [BackgroundDependencyLoader] - private void load(BeatmapManager beatmaps) - { - this.beatmaps = beatmaps; - - var working = beatmaps.GetWorkingBeatmap(beatmap); - text.Text = $"{working.Metadata.Artist} - {working.Metadata.Title} ({working.Metadata.AuthorString}) [{working.BeatmapInfo.Version}]"; - } - - private void beatmapChanged(WorkingBeatmap newBeatmap) - { - if (isSelected) - this.FadeColour(Color4.White, 100); - isSelected = false; - } - - protected override bool OnClick(InputState state) - { - if (beatmapBindable.Value.BeatmapInfo.ID == beatmap.ID) - return false; - - beatmapBindable.Value = beatmaps.GetWorkingBeatmap(beatmap); - isSelected = true; - return true; - } - - protected override bool OnHover(InputState state) - { - if (isSelected) - return false; - this.FadeColour(Color4.Yellow, 100); - return true; - } - - protected override void OnHoverLost(InputState state) - { - if (isSelected) - return; - this.FadeColour(Color4.White, 100); - } - } - } - - private class PerformanceList : CompositeDrawable - { - private readonly FillFlowContainer scores; - private APIAccess api; - - private readonly IBindable currentBeatmap = new Bindable(); - - public PerformanceList() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = scores = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 4) - }; - } - - [BackgroundDependencyLoader] - private void load(IBindableBeatmap beatmap, APIAccess api) - { - this.api = api; - - if (!api.IsLoggedIn) - { - InternalChild = new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "Please sign in to see online scores", - }; - } - - currentBeatmap.ValueChanged += beatmapChanged; - currentBeatmap.BindTo(beatmap); - } - - private GetScoresRequest lastRequest; - private void beatmapChanged(WorkingBeatmap newBeatmap) - { - if (!IsAlive) return; - - lastRequest?.Cancel(); - scores.Clear(); - - if (!api.IsLoggedIn) - return; - - lastRequest = new GetScoresRequest(newBeatmap.BeatmapInfo, newBeatmap.BeatmapInfo.Ruleset); - lastRequest.Success += res => res.Scores.ForEach(s => scores.Add(new PerformanceDisplay(s, newBeatmap.Beatmap))); - api.Queue(lastRequest); - } - - private class PerformanceDisplay : CompositeDrawable - { - private readonly OsuSpriteText text; - - private readonly Score score; - private readonly IBeatmap beatmap; - - public PerformanceDisplay(Score score, IBeatmap beatmap) - { - this.score = score; - this.beatmap = beatmap; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = text = new OsuSpriteText(); - } - - [BackgroundDependencyLoader] - private void load() - { - var ruleset = beatmap.BeatmapInfo.Ruleset.CreateInstance(); - var calculator = ruleset.CreatePerformanceCalculator(beatmap, score); - if (calculator == null) - return; - - var attributes = new Dictionary(); - double performance = calculator.Calculate(attributes); - - text.Text = $"{score.User.Username} -> online: {score.PP:n2}pp | local: {performance:n2}pp"; - } - } - } - - private class StarRatingGrid : CompositeDrawable - { - private readonly FillFlowContainer modFlow; - private readonly OsuSpriteText totalText; - private readonly FillFlowContainer categoryTexts; - - public StarRatingGrid() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - InternalChild = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - modFlow = new FillFlowContainer - { - Name = "Checkbox flow", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(4, 4) - }, - new FillFlowContainer - { - Name = "Information display", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0, 4), - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - totalText = new OsuSpriteText { TextSize = 24 }, - categoryTexts = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - } - } - } - } - }; - } - - [BackgroundDependencyLoader] - private void load(IBindableBeatmap beatmap) - { - beatmap.ValueChanged += beatmapChanged; - } - - private Cached informationCache = new Cached(); - - private Ruleset ruleset; - private WorkingBeatmap beatmap; - - private void beatmapChanged(WorkingBeatmap newBeatmap) - { - beatmap = newBeatmap; - - modFlow.Clear(); - - ruleset = newBeatmap.BeatmapInfo.Ruleset.CreateInstance(); - foreach (var mod in ruleset.GetAllMods()) - { - var checkBox = new OsuCheckbox - { - RelativeSizeAxes = Axes.None, - Width = 50, - LabelText = mod.ShortenedName - }; - - checkBox.Current.ValueChanged += v => informationCache.Invalidate(); - modFlow.Add(checkBox); - } - - informationCache.Invalidate(); - } - - protected override void Update() - { - base.Update(); - - if (ruleset == null) - return; - - if (!informationCache.IsValid) - { - totalText.Text = string.Empty; - categoryTexts.Clear(); - - var allMods = ruleset.GetAllMods().ToList(); - Mod[] activeMods = modFlow.Where(c => c.Current.Value).Select(c => allMods.First(m => m.ShortenedName == c.LabelText)).ToArray(); - - var diffCalc = ruleset.CreateDifficultyCalculator(beatmap.Beatmap, activeMods); - if (diffCalc != null) - { - var categories = new Dictionary(); - double totalSr = diffCalc.Calculate(categories); - - totalText.Text = $"Star rating: {totalSr:n2}"; - foreach (var kvp in categories) - categoryTexts.Add(new OsuSpriteText { Text = $"{kvp.Key}: {kvp.Value:n2}" }); - } - - informationCache.Validate(); - } - } - } - } -} From 8f7334874ca3ff149c6e2cc10f0e0cd667f8c40e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:04:48 +0900 Subject: [PATCH 114/186] Fix up performance calculators --- .../Difficulty/ManiaPerformanceCalculator.cs | 4 ++-- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Difficulty/OsuPerformanceCalculator.cs | 8 +++++--- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- .../Difficulty/TaikoPerformanceCalculator.cs | 6 +++--- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- .../DifficultyAdjustmentModCombinationsTest.cs | 8 ++++---- osu.Game/Beatmaps/BeatmapManager.cs | 3 +-- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- .../Rulesets/Difficulty/PerformanceCalculator.cs | 12 ++++++------ osu.Game/Rulesets/Ruleset.cs | 2 +- 11 files changed, 26 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 93652f7610..b6089b830b 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty private int countMeh; private int countMiss; - public ManiaPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { } @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty private double computeStrainValue() { // Obtain strain difficulty - double strainValue = Math.Pow(5 * Math.Max(1, Attributes["Strain"] / 0.2) - 4.0, 2.2) / 135.0; + double strainValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0; // Longer maps are worth more strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 1b7a8f77b3..ac5fbfdde0 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania { public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap); public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap); - public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score); public override IEnumerable ConvertLegacyMods(LegacyMods mods) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 57cf962fa7..3ab3cc879a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { + public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes; + private readonly int countHitCircles; private readonly int beatmapMaxCombo; @@ -37,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private int countMeh; private int countMiss; - public OsuPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); @@ -102,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeAimValue() { - double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Aim"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.AimStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + @@ -151,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeSpeedValue() { - double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Speed"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f; + double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes.SpeedStrain / 0.0675f) - 4.0f, 3.0f) / 100000.0f; // Longer maps are worth more speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) + diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 49468392f5..ce80537b93 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Osu public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap); - public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score); public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 6b1a25d667..53cfb4fd0f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -22,10 +22,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private int countMeh; private int countMiss; - public TaikoPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) : base(ruleset, beatmap, score) { - beatmapMaxCombo = beatmap.HitObjects.Count(h => h is Hit); + beatmapMaxCombo = Beatmap.HitObjects.Count(h => h is Hit); } public override double Calculate(Dictionary categoryDifficulty = null) @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeStrainValue() { - double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes["Strain"] / 0.0075) - 4.0, 2.0) / 100000.0; + double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0; // Longer maps are worth more double lengthBonus = 1 + 0.1f * Math.Min(1.0, totalHits / 1500.0); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 1b34ab68bd..7b4978694b 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap); - public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); + public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score); public override int? LegacyID => 1; diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index fd697ba3d3..49494b65b9 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -2,8 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using NUnit.Framework; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; @@ -139,14 +139,14 @@ namespace osu.Game.Tests.NonVisual private class TestDifficultyCalculator : DifficultyCalculator { public TestDifficultyCalculator(params Mod[] mods) - : base(null) + : base(null, null) { DifficultyAdjustmentMods = mods; } - public override double Calculate(Dictionary categoryDifficulty = null) => throw new NotImplementedException(); - protected override Mod[] DifficultyAdjustmentMods { get; } + + protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) => throw new NotImplementedException(); } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 895b47d62b..5e3b66646b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -366,8 +366,7 @@ namespace osu.Game.Beatmaps if (ruleset != null) { // TODO: this should be done in a better place once we actually need to dynamically update it. - var converted = new DummyConversionBeatmap(beatmap).GetPlayableBeatmap(ruleset); - beatmap.BeatmapInfo.StarDifficulty = ruleset.CreateInstance().CreateDifficultyCalculator(converted).Calculate(); + beatmap.BeatmapInfo.StarDifficulty = ruleset.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating; } else beatmap.BeatmapInfo.StarDifficulty = 0; diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index ee1fc6aec3..265c6832b2 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -62,7 +62,7 @@ namespace osu.Game.Beatmaps public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new DummyBeatmapConverter { Beatmap = beatmap }; - public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => null; + public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => null; public override string Description => "dummy"; diff --git a/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs index 07d9c80061..ba783ee87b 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceCalculator.cs @@ -13,8 +13,7 @@ namespace osu.Game.Rulesets.Difficulty { public abstract class PerformanceCalculator { - private readonly Dictionary attributes = new Dictionary(); - protected IDictionary Attributes => attributes; + protected readonly DifficultyAttributes Attributes; protected readonly Ruleset Ruleset; protected readonly IBeatmap Beatmap; @@ -22,14 +21,15 @@ namespace osu.Game.Rulesets.Difficulty protected double TimeRate { get; private set; } = 1; - protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score) + protected PerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, Score score) { Ruleset = ruleset; - Beatmap = beatmap; Score = score; - var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods); - diffCalc.Calculate(attributes); + beatmap.Mods.Value = score.Mods; + Beatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo); + + Attributes = ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods); ApplyMods(score.Mods); } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index cdc1c44306..f818523a3d 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap); - public virtual PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => null; + public virtual PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, Score score) => null; public virtual HitObjectComposer CreateHitObjectComposer() => null; From af218b3d8dd16b6ae9762c122b6fcd757ec44d8f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 16:13:21 +0900 Subject: [PATCH 115/186] No need to use properties --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 5650bc395a..50a259ae55 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyAttributes : DifficultyAttributes { - public double AimStrain { get; set; } - public double SpeedStrain { get; set; } + public double AimStrain; + public double SpeedStrain; public OsuDifficultyAttributes(Mod[] mods, double starRating) : base(mods, starRating) From c41a50bf24635c94c719eefcde8272d4147eda4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 14 Jun 2018 16:39:31 +0900 Subject: [PATCH 116/186] Fix combos ending with JuiceStreams never leaving the catcher's plate Closes #2634. --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index ae799875a9..b2d8e3f8a5 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -124,6 +124,9 @@ namespace osu.Game.Rulesets.Catch.Objects X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH }); } + + if (NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested) + lastNested.LastInCombo = LastInCombo; } public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity; From 08b9cf75e964fd3665d3aa67ccb8e4ceff5b7e6b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 17:04:31 +0900 Subject: [PATCH 117/186] Don't compute keymod difficulties for mania-specific beatmaps These don't affect the number of keys in the beatmap at all for mania-specific beatmaps. --- .../Difficulty/ManiaDifficultyCalculator.cs | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 9c091ac31a..520b9c1152 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -29,9 +29,12 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// private const double decay_weight = 0.9; + private readonly bool isForCurrentRuleset; + public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { + isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo); } protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) @@ -129,22 +132,38 @@ namespace osu.Game.Rulesets.Mania.Difficulty return difficulty; } - protected override Mod[] DifficultyAdjustmentMods => new Mod[] + protected override Mod[] DifficultyAdjustmentMods { - new ManiaModDoubleTime(), - new ManiaModHalfTime(), - new ManiaModEasy(), - new ManiaModHardRock(), - new ManiaModKey1(), - new ManiaModKey2(), - new ManiaModKey3(), - new ManiaModKey4(), - new ManiaModKey5(), - new ManiaModKey6(), - new ManiaModKey7(), - new ManiaModKey8(), - new ManiaModKey9(), - }; + get + { + if (isForCurrentRuleset) + { + return new Mod[] + { + new ManiaModDoubleTime(), + new ManiaModHalfTime(), + new ManiaModEasy(), + new ManiaModHardRock(), + }; + } + return new Mod[] + { + new ManiaModDoubleTime(), + new ManiaModHalfTime(), + new ManiaModEasy(), + new ManiaModHardRock(), + new ManiaModKey1(), + new ManiaModKey2(), + new ManiaModKey3(), + new ManiaModKey4(), + new ManiaModKey5(), + new ManiaModKey6(), + new ManiaModKey7(), + new ManiaModKey8(), + new ManiaModKey9(), + }; + } + } } } From b25a6a33ccdde95af2a05739661b211cf0d7a3fd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 19:37:21 +0900 Subject: [PATCH 118/186] Fix 1K breaking hitcircle / slider conversions --- .../Patterns/Legacy/DistanceObjectPatternGenerator.cs | 7 +++++++ .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index afa9bdbbd7..f60958d581 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -58,6 +58,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy public override Pattern Generate() { + if (TotalColumns == 1) + { + var pattern = new Pattern(); + addToPattern(pattern, 0, HitObject.StartTime, endTime); + return pattern; + } + if (spanCount > 1) { if (segmentDuration <= 90) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index cec3e18ad6..c72005e3ad 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -81,6 +81,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy public override Pattern Generate() { + if (TotalColumns == 1) + { + var pattern = new Pattern(); + addToPattern(pattern, 0); + return pattern; + } + int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0; if ((convertType & PatternType.Reverse) > 0 && PreviousPattern.HitObjects.Any()) From a3bf16e481bc5489ba809ef97e6326c565b0fc97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 19:37:32 +0900 Subject: [PATCH 119/186] Fix missing convert type --- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index c72005e3ad..339a1b4e77 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -77,6 +77,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy } else convertType |= PatternType.LowProbability; + + if ((convertType & PatternType.KeepSingle) == 0) + { + if (HitObject.Samples.Any(s => s.Name == SampleInfo.HIT_FINISH) && TotalColumns != 8) + convertType |= PatternType.Mirror; + else + convertType |= PatternType.Gathered; + } } public override Pattern Generate() From fd84afb89bfa052f9a13139721d74b8932fe1c0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 19:38:48 +0900 Subject: [PATCH 120/186] Fix non-inverted calculation --- .../Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs index 339a1b4e77..b4160dc98b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/HitObjectPatternGenerator.cs @@ -361,7 +361,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy addToCentre = false; if ((convertType & PatternType.ForceNotStack) > 0) - return getRandomNoteCount(p2 / 2, p2, (p2 + p3) / 2, p3); + return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3); switch (TotalColumns) { From 5e66b021085c1214da2c350ebe96688c5aabf0f2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 18:38:27 +0900 Subject: [PATCH 121/186] Process beatmap before generating mappings --- .../Tests/Beatmaps/BeatmapConversionTest.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 7470f6ebed..c5f74af770 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -84,19 +84,26 @@ namespace osu.Game.Tests.Beatmaps beatmap.BeatmapInfo.Ruleset = beatmap.BeatmapInfo.RulesetID == rulesetInstance.RulesetInfo.ID ? rulesetInstance.RulesetInfo : new RulesetInfo(); var result = new ConvertResult(); - var converter = rulesetInstance.CreateBeatmapConverter(beatmap); + + List>> conversions = new List>>(); + converter.ObjectConverted += (orig, converted) => { + conversions.Add(new KeyValuePair>(orig, converted)); converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); - - var mapping = new ConvertMapping { StartTime = orig.StartTime }; - foreach (var obj in converted) - mapping.Objects.AddRange(CreateConvertValue(obj)); - result.Mappings.Add(mapping); }; - converter.Convert(); + IBeatmap convertedBeatmap = converter.Convert(); + rulesetInstance.CreateBeatmapProcessor(convertedBeatmap).PostProcess(); + + foreach (var pair in conversions) + { + var mapping = new ConvertMapping { StartTime = pair.Key.StartTime }; + foreach (var obj in pair.Value) + mapping.Objects.AddRange(CreateConvertValue(obj)); + result.Mappings.Add(mapping); + } return result; } From 8d0e7abdd62c977ffc53d408430faf967604ced3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 21:17:27 +0900 Subject: [PATCH 122/186] Some rulesets don't have a beatmap processor --- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index c5f74af770..4b0da3a14b 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps var result = new ConvertResult(); var converter = rulesetInstance.CreateBeatmapConverter(beatmap); - List>> conversions = new List>>(); + var conversions = new List>>(); converter.ObjectConverted += (orig, converted) => { @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Beatmaps }; IBeatmap convertedBeatmap = converter.Convert(); - rulesetInstance.CreateBeatmapProcessor(convertedBeatmap).PostProcess(); + rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess(); foreach (var pair in conversions) { From 024d2abfe09ea3c1200a587ebcef17311d738238 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 20:26:55 +0900 Subject: [PATCH 123/186] Always generate mappings/convert values as soon as objects are converted # Conflicts: # osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs --- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 4b0da3a14b..424ebe0cf3 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -86,25 +86,19 @@ namespace osu.Game.Tests.Beatmaps var result = new ConvertResult(); var converter = rulesetInstance.CreateBeatmapConverter(beatmap); - var conversions = new List>>(); - converter.ObjectConverted += (orig, converted) => { - conversions.Add(new KeyValuePair>(orig, converted)); converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); + + var mapping = new ConvertMapping { StartTime = orig.StartTime }; + foreach (var obj in converted) + mapping.Objects.AddRange(CreateConvertValue(obj)); + result.Mappings.Add(mapping); }; IBeatmap convertedBeatmap = converter.Convert(); rulesetInstance.CreateBeatmapProcessor(convertedBeatmap)?.PostProcess(); - foreach (var pair in conversions) - { - var mapping = new ConvertMapping { StartTime = pair.Key.StartTime }; - foreach (var obj in pair.Value) - mapping.Objects.AddRange(CreateConvertValue(obj)); - result.Mappings.Add(mapping); - } - return result; } From b99b520656dc8ae9cda7fc5ef1da13801e2ae858 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 20:28:29 +0900 Subject: [PATCH 124/186] Allow convertmapping to be extended --- .../Tests/Beatmaps/BeatmapConversionTest.cs | 68 +++++++++++++++---- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 424ebe0cf3..9f15949f7b 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -16,7 +16,8 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Tests.Beatmaps { [TestFixture] - public abstract class BeatmapConversionTest + public abstract class BeatmapConversionTest + where TConvertMapping : ConvertMapping, IEquatable, new() where TConvertValue : IEquatable { private const string resource_namespace = "Testing.Beatmaps"; @@ -59,9 +60,13 @@ namespace osu.Game.Tests.Beatmaps else if (objectCounter >= expectedMapping.Objects.Count) Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n" + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); - else if (!EqualityComparer.Default.Equals(expectedMapping.Objects[objectCounter], ourMapping.Objects[objectCounter])) + else if (!expectedMapping.Equals(ourMapping)) + Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n" + + $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n" + + $"Received: {JsonConvert.SerializeObject(ourMapping)}"); + else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter])) { - Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}\n" + Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n" + $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n" + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); } @@ -90,7 +95,9 @@ namespace osu.Game.Tests.Beatmaps { converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); - var mapping = new ConvertMapping { StartTime = orig.StartTime }; + var mapping = CreateConvertMapping(); + mapping.StartTime = orig.StartTime; + foreach (var obj in converted) mapping.Objects.AddRange(CreateConvertValue(obj)); result.Mappings.Add(mapping); @@ -129,21 +136,54 @@ namespace osu.Game.Tests.Beatmaps return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}"); } - protected abstract IEnumerable CreateConvertValue(HitObject hitObject); - protected abstract Ruleset CreateRuleset(); + /// + /// Creates the conversion mapping for a . A conversion mapping stores important information about the conversion process. + /// This is generated _after_ the has been converted. + /// + /// This should be used to validate the integrity of the conversion process after a conversion has occurred. + /// + /// + protected virtual TConvertMapping CreateConvertMapping() => new TConvertMapping(); - private class ConvertMapping - { - [JsonProperty] - public double StartTime; - [JsonProperty] - public List Objects = new List(); - } + /// + /// Creates the conversion value for a . A conversion value stores information about the converted . + /// + /// This should be used to validate the integrity of the converted . + /// + /// + /// The converted . + protected abstract IEnumerable CreateConvertValue(HitObject hitObject); + + /// + /// Creates the applicable to this . + /// + /// + protected abstract Ruleset CreateRuleset(); private class ConvertResult { [JsonProperty] - public List Mappings = new List(); + public List Mappings = new List(); } } + + public abstract class BeatmapConversionTest : BeatmapConversionTest, TConvertValue> + where TConvertValue : IEquatable + { + } + + public class ConvertMapping : IEquatable> + where TConvertValue : IEquatable + { + [JsonProperty] + public double StartTime; + + [JsonIgnore] + public List Objects = new List(); + + [JsonProperty("Objects")] + private List setObjects { set => Objects = value; } + + public virtual bool Equals(ConvertMapping other) => StartTime.Equals(other?.StartTime); + } } From a4d236408378ea34fd93af06e6c77d775072c59e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 14 Jun 2018 21:29:08 +0900 Subject: [PATCH 125/186] Add one more newline --- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 9f15949f7b..cf4dda52a8 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Beatmaps else if (!expectedMapping.Equals(ourMapping)) Assert.Fail($"The conversion mapping differed for object at time {expectedMapping.StartTime}:\n" + $"Expected {JsonConvert.SerializeObject(expectedMapping)}\n" - + $"Received: {JsonConvert.SerializeObject(ourMapping)}"); + + $"Received: {JsonConvert.SerializeObject(ourMapping)}\n"); else if (!expectedMapping.Objects[objectCounter].Equals(ourMapping.Objects[objectCounter])) { Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}:\n" From 4a19f22b3d798201734ac71859204cddb815fc37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 13:38:42 +0900 Subject: [PATCH 126/186] Remove custom migration exception This was hiding the true error message from ever hitting logs. Made to help disagnose #2711. --- osu.Game/Database/OsuDbContext.cs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs index 4b0de57c4c..bf57644caf 100644 --- a/osu.Game/Database/OsuDbContext.cs +++ b/osu.Game/Database/OsuDbContext.cs @@ -181,24 +181,6 @@ namespace osu.Game.Database } } - public void Migrate() - { - try - { - Database.Migrate(); - } - catch (Exception e) - { - throw new MigrationFailedException(e); - } - } - } - - public class MigrationFailedException : Exception - { - public MigrationFailedException(Exception exception) - : base("sqlite-net migration failed", exception) - { - } + public void Migrate() => Database.Migrate(); } } From 069d939e292bc072423fe8852d2ae003e80ebfe9 Mon Sep 17 00:00:00 2001 From: Joehu Date: Thu, 14 Jun 2018 21:53:01 -0700 Subject: [PATCH 127/186] Remove "from" prefix from sources on direct panels --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 2 +- osu.Game/Overlays/Direct/DirectListPanel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 723e9e8b35..e286837746 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -149,7 +149,7 @@ namespace osu.Game.Overlays.Direct { new OsuSpriteText { - Text = $"{SetInfo.Metadata.Source}", + Text = SetInfo.Metadata.Source, TextSize = 14, Shadow = false, Colour = colours.Gray5, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 6e3483604b..812a0e2073 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -160,7 +160,7 @@ namespace osu.Game.Overlays.Direct }, new OsuSpriteText { - Text = $"from {SetInfo.Metadata.Source}", + Text = SetInfo.Metadata.Source, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, TextSize = 14, From 149d94116bef6b2cbe96aba8901922fb2de7c53c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 15:44:47 +0900 Subject: [PATCH 128/186] Fix droplets not bouncing off catcher's plate immediately --- .../Drawable/DrawableCatchHitObject.cs | 2 + .../Objects/Drawable/DrawableDroplet.cs | 2 + osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 63 +++++++++++-------- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs index 3dbda708e5..e3564b5967 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs @@ -42,6 +42,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { public virtual bool CanBePlated => false; + public virtual bool StaysOnPlate => CanBePlated; + protected DrawableCatchHitObject(CatchHitObject hitObject) : base(hitObject) { diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs index a19d67ebbe..5c8a7c4a7c 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs @@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable { private Pulp pulp; + public override bool StaysOnPlate => false; + public DrawableDroplet(Droplet h) : base(h) { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index d8c7b5130d..b62e9997d4 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -48,6 +48,16 @@ namespace osu.Game.Rulesets.Catch.UI public void OnJudgement(DrawableCatchHitObject fruit, Judgement judgement) { + void runAfterLoaded(Action action) + { + // this is required to make this run after the last caught fruit runs UpdateState at least once. + // TODO: find a better alternative + if (lastPlateableFruit.IsLoaded) + action(); + else + lastPlateableFruit.OnLoadComplete = _ => action(); + } + if (judgement.IsHit && fruit.CanBePlated) { var caughtFruit = (DrawableCatchHitObject)GetVisualRepresentation?.Invoke(fruit.HitObject); @@ -63,21 +73,17 @@ namespace osu.Game.Rulesets.Catch.UI caughtFruit.LifetimeEnd = double.MaxValue; MovableCatcher.Add(caughtFruit); - lastPlateableFruit = caughtFruit; + + if (!fruit.StaysOnPlate) + runAfterLoaded(() => MovableCatcher.Explode(caughtFruit)); + } if (fruit.HitObject.LastInCombo) { if (judgement.IsHit) - { - // this is required to make this run after the last caught fruit runs UpdateState at least once. - // TODO: find a better alternative - if (lastPlateableFruit.IsLoaded) - MovableCatcher.Explode(); - else - lastPlateableFruit.OnLoadComplete = _ => { MovableCatcher.Explode(); }; - } + runAfterLoaded(() => MovableCatcher.Explode()); else MovableCatcher.Drop(); } @@ -378,28 +384,31 @@ namespace osu.Game.Rulesets.Catch.UI var fruit = caughtFruit.ToArray(); foreach (var f in fruit) + Explode(f); + } + + public void Explode(DrawableHitObject fruit) + { + var originalX = fruit.X * Scale.X; + + if (ExplodingFruitTarget != null) { - var originalX = f.X * Scale.X; + fruit.Anchor = Anchor.TopLeft; + fruit.Position = caughtFruit.ToSpaceOfOtherDrawable(fruit.DrawPosition, ExplodingFruitTarget); - if (ExplodingFruitTarget != null) - { - f.Anchor = Anchor.TopLeft; - f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget); + caughtFruit.Remove(fruit); - caughtFruit.Remove(f); - - ExplodingFruitTarget.Add(f); - } - - f.MoveToY(f.Y - 50, 250, Easing.OutSine) - .Then() - .MoveToY(f.Y + 50, 500, Easing.InSine); - - f.MoveToX(f.X + originalX * 6, 1000); - f.FadeOut(750); - - f.Expire(); + ExplodingFruitTarget.Add(fruit); } + + fruit.MoveToY(fruit.Y - 50, 250, Easing.OutSine) + .Then() + .MoveToY(fruit.Y + 50, 500, Easing.InSine); + + fruit.MoveToX(fruit.X + originalX * 6, 1000); + fruit.FadeOut(750); + + fruit.Expire(); } private class CatcherSprite : Sprite From 1c27ef644a53340f8d3883128789ae71bbc6cb8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 16:12:11 +0900 Subject: [PATCH 129/186] Fix music controller drag activating from anywhere on the screen --- osu.Game/Overlays/MusicController.cs | 61 +++++++++++++++------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index d96bb40165..a57d5fd183 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -66,34 +66,6 @@ namespace osu.Game.Overlays AlwaysPresent = true; } - private Vector2 dragStart; - - protected override bool OnDragStart(InputState state) - { - base.OnDragStart(state); - dragStart = state.Mouse.Position; - return true; - } - - protected override bool OnDrag(InputState state) - { - if (base.OnDrag(state)) return true; - - Vector2 change = state.Mouse.Position - dragStart; - - // Diminish the drag distance as we go further to simulate "rubber band" feeling. - change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length; - - dragContainer.MoveTo(change); - return true; - } - - protected override bool OnDragEnd(InputState state) - { - dragContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic); - return base.OnDragEnd(state); - } - [BackgroundDependencyLoader] private void load(BindableBeatmap beatmap, BeatmapManager beatmaps, OsuColour colours, LocalisationEngine localisation) { @@ -103,7 +75,7 @@ namespace osu.Game.Overlays Children = new Drawable[] { - dragContainer = new Container + dragContainer = new DragContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -470,5 +442,36 @@ namespace osu.Game.Overlays sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4"); } } + + private class DragContainer : Container + { + private Vector2 dragStart; + + protected override bool OnDragStart(InputState state) + { + base.OnDragStart(state); + dragStart = state.Mouse.Position; + return true; + } + + protected override bool OnDrag(InputState state) + { + if (base.OnDrag(state)) return true; + + Vector2 change = state.Mouse.Position - dragStart; + + // Diminish the drag distance as we go further to simulate "rubber band" feeling. + change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length; + + this.MoveTo(change); + return true; + } + + protected override bool OnDragEnd(InputState state) + { + this.MoveTo(Vector2.Zero, 800, Easing.OutElastic); + return base.OnDragEnd(state); + } + } } } From a2950b1d80d6efeece366c6be4b807a88d434dc6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 16:12:18 +0900 Subject: [PATCH 130/186] Fix incorrect comment --- osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 0186a170c9..062f8d27aa 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Graphics.Containers /// /// Whether mouse input should be blocked screen-wide while this overlay is visible. - /// Performing mouse actions outside of the valid extents will hide the overlay but pass the events through. + /// Performing mouse actions outside of the valid extents will hide the overlay and block the input. /// public virtual bool BlockScreenWideMouse => BlockPassThroughMouse; From aaf3ef240e4e40a49768bf051ed8157ad1e5894e Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Fri, 15 Jun 2018 17:07:07 +0900 Subject: [PATCH 131/186] Remove easily-confused comment --- osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 062f8d27aa..0528f7b3ae 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Graphics.Containers /// /// Whether mouse input should be blocked screen-wide while this overlay is visible. - /// Performing mouse actions outside of the valid extents will hide the overlay and block the input. + /// Performing mouse actions outside of the valid extents will hide the overlay. /// public virtual bool BlockScreenWideMouse => BlockPassThroughMouse; From 5d105cd08d036d78009733546c80711c1503e592 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 15 Jun 2018 17:15:04 +0900 Subject: [PATCH 132/186] Avoid errors being logged when importing beatmaps while logged out --- osu.Game/Beatmaps/BeatmapManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 895b47d62b..0b45aa9506 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -390,6 +390,9 @@ namespace osu.Game.Beatmaps if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) return true; + if (api.State != APIState.Online) + return false; + Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database); try From 457531910294897c15cdfbc5337672d138c0ef1d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 17 Jun 2018 17:56:46 +0900 Subject: [PATCH 133/186] Privatise the proxied content --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 17 +++++++++++------ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index c07ee3a0fd..e712d62a26 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler { protected readonly Container Content; - public readonly Container ProxiedContent; + private readonly Container proxiedContent; private readonly Container nonProxiedContent; @@ -31,12 +31,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Both, Child = Content = new Container { RelativeSizeAxes = Axes.Both } }, - ProxiedContent = new Container { RelativeSizeAxes = Axes.Both } + proxiedContent = new Container { RelativeSizeAxes = Axes.Both } }; } /// - /// is proxied into an upper layer. We don't want to get masked away otherwise would too. + /// is proxied into an upper layer. We don't want to get masked away otherwise would too. /// protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; @@ -46,8 +46,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected void ProxyContent() { nonProxiedContent.Remove(Content); - ProxiedContent.Remove(Content); - ProxiedContent.Add(Content); + proxiedContent.Remove(Content); + proxiedContent.Add(Content); } /// @@ -55,11 +55,16 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected void UnproxyContent() { - ProxiedContent.Remove(Content); + proxiedContent.Remove(Content); nonProxiedContent.Remove(Content); nonProxiedContent.Add(Content); } + /// + /// Creates a proxy for the content of this . + /// + public Drawable CreateProxiedContent() => proxiedContent.CreateProxy(); + public abstract bool OnPressed(TaikoAction action); public virtual bool OnReleased(TaikoAction action) => false; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index c638f807fe..7fdd3cd1e2 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -218,7 +218,7 @@ namespace osu.Game.Rulesets.Taiko.UI var taikoObject = h as DrawableTaikoHitObject; if (taikoObject != null) - topLevelHitContainer.Add(taikoObject.ProxiedContent.CreateProxy()); + topLevelHitContainer.Add(taikoObject.CreateProxiedContent()); } internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) From 0a99d21938a252071189eab06d40f909d098e138 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sun, 17 Jun 2018 18:01:28 +0900 Subject: [PATCH 134/186] Use the passed-in ruleset --- osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 520b9c1152..5d5adb8e66 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty public ManiaDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { - isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(new ManiaRuleset().RulesetInfo); + isForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); } protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate) From 6c100caba763b333cd099e37033c70e02cac224b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 15:09:03 +0900 Subject: [PATCH 135/186] Use existing instance of beatmap rather than adding more resources --- .../Beatmaps/IO/ImportBeatmapTest.cs | 4 +- osu.Game.Tests/Visual/TestCaseWaveform.cs | 16 +----- osu.Game.Tests/WaveformTestBeatmap.cs | 55 +++++++++++++++++++ 3 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Tests/WaveformTestBeatmap.cs diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 1c9696901c..616ba132fd 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Beatmaps.IO [TestFixture] public class ImportBeatmapTest { - private const string osz_path = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; + public const string TEST_OSZ_PATH = @"../../../../osu-resources/osu.Game.Resources/Beatmaps/241526 Soleily - Renatus.osz"; [Test] public void TestImportWhenClosed() @@ -265,7 +265,7 @@ namespace osu.Game.Tests.Beatmaps.IO private string createTemporaryBeatmap() { var temp = Path.GetTempFileName() + ".osz"; - File.Copy(osz_path, temp, true); + File.Copy(TEST_OSZ_PATH, temp, true); Assert.IsTrue(File.Exists(temp)); return temp; } diff --git a/osu.Game.Tests/Visual/TestCaseWaveform.cs b/osu.Game.Tests/Visual/TestCaseWaveform.cs index 983b98016e..46d46863ad 100644 --- a/osu.Game.Tests/Visual/TestCaseWaveform.cs +++ b/osu.Game.Tests/Visual/TestCaseWaveform.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays; namespace osu.Game.Tests.Visual { @@ -20,22 +19,14 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { + Beatmap.Value = new WaveformTestBeatmap(); + FillFlowContainer flow; Child = flow = new FillFlowContainer { RelativeSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 10), - Children = new Drawable[] - { - new MusicController - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Y = 100, - State = Visibility.Visible - }, - } }; for (int i = 1; i <= 16; i *= 2) @@ -44,10 +35,9 @@ namespace osu.Game.Tests.Visual { RelativeSizeAxes = Axes.Both, Resolution = 1f / i, + Waveform = Beatmap.Value.Waveform, }; - Beatmap.ValueChanged += b => newDisplay.Waveform = b.Waveform; - flow.Add(new Container { RelativeSizeAxes = Axes.X, diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs new file mode 100644 index 0000000000..17aa7db14d --- /dev/null +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.IO; +using System.Linq; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Formats; +using osu.Game.IO.Archives; +using osu.Game.Tests.Beatmaps.IO; + +namespace osu.Game.Tests +{ + /// + /// A that is used for testcases that include waveforms. + /// + public class WaveformTestBeatmap : WorkingBeatmap + { + private readonly ZipArchiveReader reader; + private readonly FileStream stream; + + public WaveformTestBeatmap() + : base(new BeatmapInfo()) + { + stream = File.OpenRead(ImportBeatmapTest.TEST_OSZ_PATH); + reader = new ZipArchiveReader(stream); + } + + public override void Dispose() + { + base.Dispose(); + stream?.Dispose(); + reader?.Dispose(); + } + + protected override IBeatmap GetBeatmap() => createTestBeatmap(); + + protected override Texture GetBackground() => null; + + protected override Waveform GetWaveform() => new Waveform(getAudioStream()); + + protected override Track GetTrack() => new TrackBass(getAudioStream()); + + private Stream getAudioStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".mp3"))); + private Stream getBeatmapStream() => reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu"))); + + private Beatmap createTestBeatmap() + { + using (var beatmapStream = getBeatmapStream()) + using (var beatmapReader = new StreamReader(beatmapStream)) + return Decoder.GetDecoder(beatmapReader).Decode(beatmapReader); + } + } +} From 0695615c6a21ff53e11c6e53ef52147841304b66 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 13 Jun 2018 15:10:08 +0900 Subject: [PATCH 136/186] Remove MusicController from compose timeline testcase --- .../Visual/TestCaseEditorComposeTimeline.cs | 104 +++++++++++++++++- 1 file changed, 98 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index c0557982fb..bb0e6156f6 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -4,11 +4,17 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Configuration; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Overlays; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using OpenTK.Graphics; namespace osu.Game.Tests.Visual { @@ -17,15 +23,23 @@ namespace osu.Game.Tests.Visual { public override IReadOnlyList RequiredTypes => new[] { typeof(TimelineArea), typeof(Timeline), typeof(TimelineButton) }; - public TestCaseEditorComposeTimeline() + [BackgroundDependencyLoader] + private void load() { + Beatmap.Value = new WaveformTestBeatmap(); + Children = new Drawable[] { - new MusicController + new FillFlowContainer { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - State = Visibility.Visible + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + Children = new Drawable[] + { + new StartStopButton(), + new AudioVisualiser(), + } }, new TimelineArea { @@ -36,5 +50,83 @@ namespace osu.Game.Tests.Visual } }; } + + private class AudioVisualiser : CompositeDrawable + { + private readonly Drawable marker; + + private readonly IBindable beatmap = new Bindable(); + private IAdjustableClock adjustableClock; + + public AudioVisualiser() + { + Size = new Vector2(250, 25); + + InternalChildren = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.25f, + }, + marker = new Box + { + RelativePositionAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Width = 2, + } + }; + } + + [BackgroundDependencyLoader] + private void load(IAdjustableClock adjustableClock, IBindableBeatmap beatmap) + { + this.adjustableClock = adjustableClock; + this.beatmap.BindTo(beatmap); + } + + protected override void Update() + { + base.Update(); + marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); + } + } + + private class StartStopButton : Button + { + private IAdjustableClock adjustableClock; + private bool started; + + public StartStopButton() + { + BackgroundColour = Color4.SlateGray; + Size = new Vector2(100, 50); + Text = "Start"; + + Action = onClick; + } + + [BackgroundDependencyLoader] + private void load(IAdjustableClock adjustableClock) + { + this.adjustableClock = adjustableClock; + } + + private void onClick() + { + if (started) + { + adjustableClock.Stop(); + Text = "Start"; + } + else + { + adjustableClock.Start(); + Text = "Stop"; + } + + started = !started; + } + } } } From 08f172ba982f8c4880a516dc565e373b3f7d0ab0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 15 Jun 2018 15:38:19 +0900 Subject: [PATCH 137/186] Make testcase work on appveyor (no BASS) --- osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index bb0e6156f6..5aa17bca7d 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -88,7 +88,9 @@ namespace osu.Game.Tests.Visual protected override void Update() { base.Update(); - marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); + + if (beatmap.Value.Track.IsLoaded) + marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length); } } From 5b344525e1889e6c4fbd8a5cedccc812827a314e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 00:27:18 +0900 Subject: [PATCH 138/186] Move proxy state check to base class --- .../Objects/Drawables/DrawableSwell.cs | 7 +------ .../Objects/Drawables/DrawableTaikoHitObject.cs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 1f571544d8..df36a475d6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -34,7 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private int userHits; - private bool hasProxied; private readonly SwellSymbolPiece symbol; public DrawableSwell(Swell swell) @@ -172,7 +171,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { case ArmedState.Idle: - hasProxied = false; UnproxyContent(); break; case ArmedState.Hit: @@ -193,11 +191,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables X = Math.Max(0, X); double t = Math.Min(HitObject.StartTime, Time.Current); - if (t == HitObject.StartTime && !hasProxied) - { + if (t == HitObject.StartTime) ProxyContent(); - hasProxied = true; - } } private bool? lastWasCentre; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index e712d62a26..a6d61f1a5a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -40,23 +40,31 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; + private bool isProxied; + /// /// Moves to a layer proxied above the playfield. + /// Does nothing is content is already proxied. /// protected void ProxyContent() { + if (isProxied) return; + isProxied = true; + nonProxiedContent.Remove(Content); - proxiedContent.Remove(Content); proxiedContent.Add(Content); } /// /// Moves to the normal hitobject layer. + /// Does nothing is content is not currently proxied. /// protected void UnproxyContent() { + if (!isProxied) return; + isProxied = false; + proxiedContent.Remove(Content); - nonProxiedContent.Remove(Content); nonProxiedContent.Add(Content); } From 6fa72c510f2b0229267053a4d7e460f69ce0f309 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 00:48:35 +0900 Subject: [PATCH 139/186] Avoid listing the base mods twice --- .../Difficulty/ManiaDifficultyCalculator.cs | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 5d5adb8e66..5fa113224d 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -136,23 +136,20 @@ namespace osu.Game.Rulesets.Mania.Difficulty { get { - if (isForCurrentRuleset) - { - return new Mod[] - { - new ManiaModDoubleTime(), - new ManiaModHalfTime(), - new ManiaModEasy(), - new ManiaModHardRock(), - }; - } - - return new Mod[] + var mods = new Mod[] { new ManiaModDoubleTime(), new ManiaModHalfTime(), new ManiaModEasy(), new ManiaModHardRock(), + }; + + if (isForCurrentRuleset) + return mods; + + // if we are a convert, we can be played in any key mod. + return mods.Concat(new Mod[] + { new ManiaModKey1(), new ManiaModKey2(), new ManiaModKey3(), @@ -162,7 +159,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty new ManiaModKey7(), new ManiaModKey8(), new ManiaModKey9(), - }; + }).ToArray(); } } } From 31f9d0161df4b9f2fd19e6a7e9304f52766d2154 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 03:03:09 +0900 Subject: [PATCH 140/186] Add a comment about precision scroll behaviour --- .../Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs index ed26c28c80..0bfea68e50 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs @@ -100,7 +100,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline protected override bool OnScroll(InputState state) { if (state.Mouse.HasPreciseScroll) + // for now, we don't support zoom when using a precision scroll device. this needs gesture support. return base.OnScroll(state); + setZoomTarget(zoomTarget + state.Mouse.ScrollDelta.Y, zoomedContent.ToLocalSpace(state.Mouse.NativeState.Position).X); return true; } From bec6e3083ec27fd25205a343470f0c9c6ad7a43b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 03:19:21 +0900 Subject: [PATCH 141/186] Remove scrollbar depth change as scrollbar is hidden now --- osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 489233e256..36f76b013a 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -45,9 +45,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline // We don't want the centre marker to scroll AddInternal(new CentreMarker()); - // Make sure that the scrollbar is above the centre marker - ChangeInternalChildDepth(Scrollbar, -1); - WaveformVisible.ValueChanged += visible => waveform.FadeTo(visible ? 1 : 0, 200, Easing.OutQuint); Beatmap.BindTo(beatmap); From b1d059a67dbe34b17d6389b3a97b33a463ecc0ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 04:31:47 +0900 Subject: [PATCH 142/186] Add some colours to the compose-mode timeline --- .../Screens/Edit/Screens/Compose/Timeline/Timeline.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs index 36f76b013a..e993d36551 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Configuration; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Input; @@ -31,14 +32,17 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline private WaveformGraph waveform; [BackgroundDependencyLoader] - private void load(IBindableBeatmap beatmap, IAdjustableClock adjustableClock) + private void load(IBindableBeatmap beatmap, IAdjustableClock adjustableClock, OsuColour colours) { this.adjustableClock = adjustableClock; Child = waveform = new WaveformGraph { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.FromHex("222"), + Colour = colours.Blue.Opacity(0.2f), + LowColour = colours.BlueLighter, + MidColour = colours.BlueDark, + HighColour = colours.BlueDarker, Depth = float.MaxValue }; From 8c671f93fc9476439b4e306a0c0c7ba2299603be Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 18 Jun 2018 19:32:04 +0900 Subject: [PATCH 143/186] Always perform non-seeked scroll in the editor while audio is playing --- osu.Game/Screens/Edit/Editor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d4f66c2f09..379484bae6 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -181,9 +181,9 @@ namespace osu.Game.Screens.Edit protected override bool OnScroll(InputState state) { if (state.Mouse.ScrollDelta.X + state.Mouse.ScrollDelta.Y > 0) - clock.SeekBackward(true); + clock.SeekBackward(!clock.IsRunning); else - clock.SeekForward(true); + clock.SeekForward(!clock.IsRunning); return true; } From 4aa89de2d76d38af34f2f19b9ef6ad7858d3c974 Mon Sep 17 00:00:00 2001 From: Tom Arrow Date: Mon, 18 Jun 2018 17:22:01 +0200 Subject: [PATCH 144/186] Fix reverse arrow displayed with incorrect angle --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs index b3bc2930d8..26f3ee6bb4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Drawables; using OpenTK; using osu.Game.Graphics; @@ -89,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // find the next vector2 in the curve which is not equal to our current position to infer a rotation. for (int i = searchStart; i >= 0 && i < curve.Count; i += direction) { - if (curve[i] == Position) + if (Precision.AlmostEquals(curve[i], Position)) continue; Rotation = MathHelper.RadiansToDegrees((float)Math.Atan2(curve[i].Y - Position.Y, curve[i].X - Position.X)); From a0f1143287c884d41a67338382e96d5c077df838 Mon Sep 17 00:00:00 2001 From: Michael Manis Date: Mon, 18 Jun 2018 19:14:44 -0400 Subject: [PATCH 145/186] Add padding to 'show more' button --- osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index 1e0406c125..b1b5e3a075 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -64,6 +64,7 @@ namespace osu.Game.Overlays.Profile.Sections { TextSize = 14, Text = "show more", + Padding = new MarginPadding {Top = 10, Bottom = 10, Left = 15, Right = 15 }, } }, ShowMoreLoading = new LoadingAnimation From 15f3a05c831f637c94fc33a958c0eb6c5963e8b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Jun 2018 19:28:21 +0900 Subject: [PATCH 146/186] Update rider configuration names --- .../{VisualTests__netcoreapp2_1_.xml => VisualTests.xml} | 5 ++--- .../runConfigurations/{osu___netcoreapp2_1_.xml => osu_.xml} | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) rename .idea/.idea.osu/.idea/runConfigurations/{VisualTests__netcoreapp2_1_.xml => VisualTests.xml} (87%) rename .idea/.idea.osu/.idea/runConfigurations/{osu___netcoreapp2_1_.xml => osu_.xml} (87%) diff --git a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_1_.xml b/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml similarity index 87% rename from .idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_1_.xml rename to .idea/.idea.osu/.idea/runConfigurations/VisualTests.xml index 2d3a848922..bf5a1f64e0 100644 --- a/.idea/.idea.osu/.idea/runConfigurations/VisualTests__netcoreapp2_1_.xml +++ b/.idea/.idea.osu/.idea/runConfigurations/VisualTests.xml @@ -1,12 +1,11 @@ - +