From d437c1d7ec386e8ca72ab8ffb6f5e3a6f143e463 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Thu, 8 Feb 2018 23:28:42 +0300 Subject: [PATCH 01/58] Introduce PlayerBase class --- osu.Game/Screens/Play/Player.cs | 96 ++++----------------------- osu.Game/Screens/Play/PlayerBase.cs | 84 +++++++++++++++++++++++ osu.Game/Screens/Play/PlayerLoader.cs | 7 +- osu.Game/osu.Game.csproj | 1 + 4 files changed, 99 insertions(+), 89 deletions(-) create mode 100644 osu.Game/Screens/Play/PlayerBase.cs diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 72864482d5..0f15592b72 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -5,9 +5,6 @@ using System; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -18,31 +15,23 @@ using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Configuration; -using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Play.BreaksOverlay; using osu.Game.Screens.Ranking; -using osu.Game.Storyboards.Drawables; -using OpenTK; namespace osu.Game.Screens.Play { - public class Player : OsuScreen, IProvideCursor + public class Player : PlayerBase, IProvideCursor { - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - public override bool ShowOverlaysOnEnter => false; public Action RestartRequested; - public override bool AllowBeatmapRulesetChange => false; - public bool HasFailed { get; private set; } public bool AllowPause { get; set; } = true; @@ -67,39 +56,16 @@ namespace osu.Game.Screens.Play private ScoreProcessor scoreProcessor; protected RulesetContainer RulesetContainer; - #region User Settings - - private Bindable dimLevel; - private Bindable blurLevel; - private Bindable showStoryboard; - private Bindable mouseWheelDisabled; - private Bindable userAudioOffset; - - private SampleChannel sampleRestart; - - #endregion - - private Container storyboardContainer; - private DrawableStoryboard storyboard; - private HUDOverlay hudOverlay; private FailOverlay failOverlay; private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true; [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuConfigManager config, APIAccess api) + private void load(OsuConfigManager config, APIAccess api) { this.api = api; - dimLevel = config.GetBindable(OsuSetting.DimLevel); - blurLevel = config.GetBindable(OsuSetting.BlurLevel); - showStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); - - mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); - - sampleRestart = audio.Sample.Get(@"Gameplay/restart"); - WorkingBeatmap working = Beatmap.Value; Beatmap beatmap; @@ -150,15 +116,14 @@ namespace osu.Game.Screens.Play offsetClock = new FramedOffsetClock(decoupledClock); - userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - userAudioOffset.ValueChanged += v => offsetClock.Offset = v; - userAudioOffset.TriggerChange(); + UserAudioOffset.ValueChanged += v => offsetClock.Offset = v; + UserAudioOffset.TriggerChange(); scoreProcessor = RulesetContainer.CreateScoreProcessor(); Children = new Drawable[] { - storyboardContainer = new Container + StoryboardContainer = new Container { RelativeSizeAxes = Axes.Both, Clock = offsetClock, @@ -219,8 +184,8 @@ namespace osu.Game.Screens.Play } }; - if (showStoryboard) - initializeStoryboard(false); + if (ShowStoryboard) + InitializeStoryboard(false); // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; @@ -239,22 +204,9 @@ namespace osu.Game.Screens.Play mod.ApplyToClock(adjustableSourceClock); } - private void initializeStoryboard(bool asyncLoad) - { - var beatmap = Beatmap.Value; - - storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); - storyboard.Masking = true; - - if (asyncLoad) - LoadComponentAsync(storyboard, storyboardContainer.Add); - else - storyboardContainer.Add(storyboard); - } - public void Restart() { - sampleRestart?.Play(); + SampleRestart?.Play(); ValidForResume = false; RestartRequested?.Invoke(); Exit(); @@ -310,10 +262,10 @@ namespace osu.Game.Screens.Play if (!loadedSuccessfully) return; - dimLevel.ValueChanged += _ => updateBackgroundElements(); - blurLevel.ValueChanged += _ => updateBackgroundElements(); - showStoryboard.ValueChanged += _ => updateBackgroundElements(); - updateBackgroundElements(); + DimLevel.ValueChanged += _ => UpdateBackgroundElements(); + BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); + ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); + UpdateBackgroundElements(); Content.Alpha = 0; Content @@ -368,28 +320,6 @@ namespace osu.Game.Screens.Play return true; } - private void updateBackgroundElements() - { - if (!IsCurrentScreen) return; - - const float duration = 800; - - var opacity = 1 - (float)dimLevel; - - if (showStoryboard && storyboard == null) - initializeStoryboard(true); - - var beatmap = Beatmap.Value; - var storyboardVisible = showStoryboard && beatmap.Storyboard.HasDrawable; - - storyboardContainer - .FadeColour(OsuColour.Gray(opacity), duration, Easing.OutQuint) - .FadeTo(storyboardVisible && opacity > 0 ? 1 : 0, duration, Easing.OutQuint); - - (Background as BackgroundScreenBeatmap)?.BlurTo(new Vector2((float)blurLevel.Value * 25), duration, Easing.OutQuint); - Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? opacity : 0, duration, Easing.OutQuint); - } - private void fadeOut() { const float fade_out_duration = 250; @@ -402,6 +332,6 @@ namespace osu.Game.Screens.Play Background?.FadeTo(1f, fade_out_duration); } - protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value && !pauseContainer.IsPaused; + protected override bool OnWheel(InputState state) => MouseWheelDisabled.Value && !pauseContainer.IsPaused; } } diff --git a/osu.Game/Screens/Play/PlayerBase.cs b/osu.Game/Screens/Play/PlayerBase.cs new file mode 100644 index 0000000000..c5a7e52de7 --- /dev/null +++ b/osu.Game/Screens/Play/PlayerBase.cs @@ -0,0 +1,84 @@ +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Screens.Backgrounds; +using osu.Game.Storyboards.Drawables; +using OpenTK; + +namespace osu.Game.Screens.Play +{ + public abstract class PlayerBase : OsuScreen + { + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); + public override bool AllowBeatmapRulesetChange => false; + + #region User Settings + + protected Bindable DimLevel; + protected Bindable BlurLevel; + protected Bindable ShowStoryboard; + protected Bindable MouseWheelDisabled; + protected Bindable UserAudioOffset; + + protected SampleChannel SampleRestart; + + #endregion + + protected DrawableStoryboard Storyboard; + protected Container StoryboardContainer; + + [BackgroundDependencyLoader] + private void load(AudioManager audio, OsuConfigManager config) + { + DimLevel = config.GetBindable(OsuSetting.DimLevel); + BlurLevel = config.GetBindable(OsuSetting.BlurLevel); + ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); + + MouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); + + SampleRestart = audio.Sample.Get(@"Gameplay/restart"); + + UserAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + } + + protected void UpdateBackgroundElements() + { + if (!IsCurrentScreen) return; + + const float duration = 800; + + var opacity = 1 - (float)DimLevel; + + if (ShowStoryboard && Storyboard == null) + InitializeStoryboard(true); + + var beatmap = Beatmap.Value; + var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable; + + StoryboardContainer + .FadeColour(OsuColour.Gray(opacity), duration, Easing.OutQuint) + .FadeTo(storyboardVisible && opacity > 0 ? 1 : 0, duration, Easing.OutQuint); + + (Background as BackgroundScreenBeatmap)?.BlurTo(new Vector2((float)BlurLevel.Value * 25), duration, Easing.OutQuint); + Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? opacity : 0, duration, Easing.OutQuint); + } + + protected void InitializeStoryboard(bool asyncLoad) + { + var beatmap = Beatmap.Value; + + Storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); + Storyboard.Masking = true; + + if (asyncLoad) + LoadComponentAsync(Storyboard, StoryboardContainer.Add); + else + StoryboardContainer.Add(Storyboard); + } + } +} diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 2950990779..0c6368c714 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -9,7 +9,6 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Screens.Backgrounds; using OpenTK; using osu.Framework.Localisation; using osu.Game.Screens.Menu; @@ -17,7 +16,7 @@ using osu.Game.Screens.Play.PlayerSettings; namespace osu.Game.Screens.Play { - public class PlayerLoader : OsuScreen + public class PlayerLoader : PlayerBase { private Player player; @@ -27,10 +26,6 @@ namespace osu.Game.Screens.Play private bool showOverlays = true; public override bool ShowOverlaysOnEnter => showOverlays; - public override bool AllowBeatmapRulesetChange => false; - - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - public PlayerLoader(Player player) { this.player = player; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6542160b97..cc5f5b92da 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -340,6 +340,7 @@ + From a860dd720893bf9f2eb950c64ef2d720477e7536 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Fri, 9 Feb 2018 00:06:24 +0300 Subject: [PATCH 02/58] =?UTF-8?q?Preview=20visual=20settings=20at=20the=20?= =?UTF-8?q?=E2=80=9Cloading=E2=80=9D=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- osu.Game/Screens/Play/Player.cs | 5 +---- osu.Game/Screens/Play/PlayerBase.cs | 13 ++++++++++++- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0f15592b72..8ebee96bae 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -262,10 +262,7 @@ namespace osu.Game.Screens.Play if (!loadedSuccessfully) return; - DimLevel.ValueChanged += _ => UpdateBackgroundElements(); - BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); - ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); - UpdateBackgroundElements(); + ConfigureBackgroundUpdate(); Content.Alpha = 0; Content diff --git a/osu.Game/Screens/Play/PlayerBase.cs b/osu.Game/Screens/Play/PlayerBase.cs index c5a7e52de7..b725b739c9 100644 --- a/osu.Game/Screens/Play/PlayerBase.cs +++ b/osu.Game/Screens/Play/PlayerBase.cs @@ -46,6 +46,14 @@ namespace osu.Game.Screens.Play UserAudioOffset = config.GetBindable(OsuSetting.AudioOffset); } + protected void ConfigureBackgroundUpdate() + { + DimLevel.ValueChanged += _ => UpdateBackgroundElements(); + BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); + ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); + UpdateBackgroundElements(); + } + protected void UpdateBackgroundElements() { if (!IsCurrentScreen) return; @@ -60,7 +68,7 @@ namespace osu.Game.Screens.Play var beatmap = Beatmap.Value; var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable; - StoryboardContainer + StoryboardContainer? .FadeColour(OsuColour.Gray(opacity), duration, Easing.OutQuint) .FadeTo(storyboardVisible && opacity > 0 ? 1 : 0, duration, Easing.OutQuint); @@ -70,6 +78,9 @@ namespace osu.Game.Screens.Play protected void InitializeStoryboard(bool asyncLoad) { + if (StoryboardContainer == null) + return; + var beatmap = Beatmap.Value; Storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 0c6368c714..a4284efddb 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -88,7 +88,7 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); - Background.FadeTo(0.4f, 250); + ConfigureBackgroundUpdate(); Content.ScaleTo(0.7f); From 4535e09607cda38faad7f4c146819b01de75a593 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Fri, 9 Feb 2018 00:36:31 +0300 Subject: [PATCH 03/58] Add missing license header --- osu.Game/Screens/Play/PlayerBase.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerBase.cs b/osu.Game/Screens/Play/PlayerBase.cs index b725b739c9..5f22645361 100644 --- a/osu.Game/Screens/Play/PlayerBase.cs +++ b/osu.Game/Screens/Play/PlayerBase.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// 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.Sample; using osu.Framework.Configuration; From c57e8785e23a01145b395da7fea09854bdb10f4e Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Thu, 15 Feb 2018 23:57:53 +0300 Subject: [PATCH 04/58] Move all storyboard loading to Player itself --- osu.Game/Screens/Play/Player.cs | 56 +++++++++-- osu.Game/Screens/Play/PlayerBase.cs | 98 ------------------- osu.Game/Screens/Play/PlayerLoader.cs | 10 +- .../Play/ScreenWithBeatmapBackground.cs | 58 +++++++++++ osu.Game/osu.Game.csproj | 2 +- 5 files changed, 118 insertions(+), 106 deletions(-) delete mode 100644 osu.Game/Screens/Play/PlayerBase.cs create mode 100644 osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 8ebee96bae..38525b18b9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -5,6 +5,8 @@ using System; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -14,7 +16,7 @@ using osu.Framework.Screens; using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; -using osu.Game.Configuration; +using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; using osu.Game.Rulesets; @@ -23,10 +25,11 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.BreaksOverlay; using osu.Game.Screens.Ranking; +using osu.Game.Storyboards.Drawables; namespace osu.Game.Screens.Play { - public class Player : PlayerBase, IProvideCursor + public class Player : ScreenWithBeatmapBackground, IProvideCursor { public override bool ShowOverlaysOnEnter => false; @@ -53,18 +56,24 @@ namespace osu.Game.Screens.Play private APIAccess api; + private SampleChannel sampleRestart; + private ScoreProcessor scoreProcessor; protected RulesetContainer RulesetContainer; private HUDOverlay hudOverlay; private FailOverlay failOverlay; + private DrawableStoryboard storyboard; + private Container storyboardContainer; + private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true; [BackgroundDependencyLoader] - private void load(OsuConfigManager config, APIAccess api) + private void load(AudioManager audio, APIAccess api) { this.api = api; + sampleRestart = audio.Sample.Get(@"Gameplay/restart"); WorkingBeatmap working = Beatmap.Value; Beatmap beatmap; @@ -123,7 +132,7 @@ namespace osu.Game.Screens.Play Children = new Drawable[] { - StoryboardContainer = new Container + storyboardContainer = new Container { RelativeSizeAxes = Axes.Both, Clock = offsetClock, @@ -185,7 +194,7 @@ namespace osu.Game.Screens.Play }; if (ShowStoryboard) - InitializeStoryboard(false); + initializeStoryboard(false); // Bind ScoreProcessor to ourselves scoreProcessor.AllJudged += onCompletion; @@ -206,7 +215,7 @@ namespace osu.Game.Screens.Play public void Restart() { - SampleRestart?.Play(); + sampleRestart?.Play(); ValidForResume = false; RestartRequested?.Invoke(); Exit(); @@ -330,5 +339,40 @@ namespace osu.Game.Screens.Play } protected override bool OnWheel(InputState state) => MouseWheelDisabled.Value && !pauseContainer.IsPaused; + + private void initializeStoryboard(bool asyncLoad) + { + if (storyboardContainer == null) + return; + + var beatmap = Beatmap.Value; + + storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); + storyboard.Masking = true; + + if (asyncLoad) + LoadComponentAsync(storyboard, storyboardContainer.Add); + else + storyboardContainer.Add(storyboard); + } + + protected override void UpdateBackgroundElements() + { + if (!IsCurrentScreen) return; + + base.UpdateBackgroundElements(); + + if (ShowStoryboard && storyboard == null) + initializeStoryboard(true); + + var beatmap = Beatmap.Value; + var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable; + + storyboardContainer? + .FadeColour(OsuColour.Gray(Opacity), Duration, Easing.OutQuint) + .FadeTo(storyboardVisible && Opacity > 0 ? 1 : 0, Duration, Easing.OutQuint); + + Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? Opacity : 0, Duration, Easing.OutQuint); + } } } diff --git a/osu.Game/Screens/Play/PlayerBase.cs b/osu.Game/Screens/Play/PlayerBase.cs deleted file mode 100644 index 5f22645361..0000000000 --- a/osu.Game/Screens/Play/PlayerBase.cs +++ /dev/null @@ -1,98 +0,0 @@ -// 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.Sample; -using osu.Framework.Configuration; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Screens.Backgrounds; -using osu.Game.Storyboards.Drawables; -using OpenTK; - -namespace osu.Game.Screens.Play -{ - public abstract class PlayerBase : OsuScreen - { - protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); - public override bool AllowBeatmapRulesetChange => false; - - #region User Settings - - protected Bindable DimLevel; - protected Bindable BlurLevel; - protected Bindable ShowStoryboard; - protected Bindable MouseWheelDisabled; - protected Bindable UserAudioOffset; - - protected SampleChannel SampleRestart; - - #endregion - - protected DrawableStoryboard Storyboard; - protected Container StoryboardContainer; - - [BackgroundDependencyLoader] - private void load(AudioManager audio, OsuConfigManager config) - { - DimLevel = config.GetBindable(OsuSetting.DimLevel); - BlurLevel = config.GetBindable(OsuSetting.BlurLevel); - ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); - - MouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); - - SampleRestart = audio.Sample.Get(@"Gameplay/restart"); - - UserAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - } - - protected void ConfigureBackgroundUpdate() - { - DimLevel.ValueChanged += _ => UpdateBackgroundElements(); - BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); - ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); - UpdateBackgroundElements(); - } - - protected void UpdateBackgroundElements() - { - if (!IsCurrentScreen) return; - - const float duration = 800; - - var opacity = 1 - (float)DimLevel; - - if (ShowStoryboard && Storyboard == null) - InitializeStoryboard(true); - - var beatmap = Beatmap.Value; - var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable; - - StoryboardContainer? - .FadeColour(OsuColour.Gray(opacity), duration, Easing.OutQuint) - .FadeTo(storyboardVisible && opacity > 0 ? 1 : 0, duration, Easing.OutQuint); - - (Background as BackgroundScreenBeatmap)?.BlurTo(new Vector2((float)BlurLevel.Value * 25), duration, Easing.OutQuint); - Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? opacity : 0, duration, Easing.OutQuint); - } - - protected void InitializeStoryboard(bool asyncLoad) - { - if (StoryboardContainer == null) - return; - - var beatmap = Beatmap.Value; - - Storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); - Storyboard.Masking = true; - - if (asyncLoad) - LoadComponentAsync(Storyboard, StoryboardContainer.Add); - else - StoryboardContainer.Add(Storyboard); - } - } -} diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a4284efddb..fa5ed6365f 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Play.PlayerSettings; namespace osu.Game.Screens.Play { - public class PlayerLoader : PlayerBase + public class PlayerLoader : ScreenWithBeatmapBackground { private Player player; @@ -263,5 +263,13 @@ namespace osu.Game.Screens.Play }; } } + + protected override void UpdateBackgroundElements() + { + if (!IsCurrentScreen) return; + + base.UpdateBackgroundElements(); + Background?.FadeTo(Opacity, Duration, Easing.OutQuint); + } } } diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs new file mode 100644 index 0000000000..83346d677c --- /dev/null +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -0,0 +1,58 @@ +// 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.Game.Configuration; +using osu.Game.Screens.Backgrounds; +using OpenTK; + +namespace osu.Game.Screens.Play +{ + public abstract class ScreenWithBeatmapBackground : OsuScreen + { + protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); + public override bool AllowBeatmapRulesetChange => false; + + protected float Duration => 800; + protected float Opacity => 1 - (float)DimLevel; + + #region User Settings + + protected Bindable DimLevel; + protected Bindable BlurLevel; + protected Bindable ShowStoryboard; + protected Bindable MouseWheelDisabled; + protected Bindable UserAudioOffset; + + #endregion + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + DimLevel = config.GetBindable(OsuSetting.DimLevel); + BlurLevel = config.GetBindable(OsuSetting.BlurLevel); + ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); + + MouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); + + UserAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + } + + protected void ConfigureBackgroundUpdate() + { + DimLevel.ValueChanged += _ => UpdateBackgroundElements(); + BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); + ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); + UpdateBackgroundElements(); + } + + protected virtual void UpdateBackgroundElements() + { + if (!IsCurrentScreen) return; + + (Background as BackgroundScreenBeatmap)?.BlurTo(new Vector2((float)BlurLevel.Value * 25), Duration, Easing.OutQuint); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index cc5f5b92da..b9ab6e7c59 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -340,7 +340,7 @@ - + From 9760f30ce97637256b963cac3267c9ef3d8542b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Feb 2018 12:08:21 +0900 Subject: [PATCH 05/58] Tidy things up to make more sense --- osu.Game/Screens/Play/Player.cs | 9 +++++---- osu.Game/Screens/Play/PlayerLoader.cs | 8 -------- osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs | 9 ++++++--- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 96ae4c7872..467332dbb9 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -347,7 +347,7 @@ namespace osu.Game.Screens.Play var beatmap = Beatmap.Value; - storyboard = beatmap.Storyboard.CreateDrawable(Beatmap.Value); + storyboard = beatmap.Storyboard.CreateDrawable(); storyboard.Masking = true; if (asyncLoad) @@ -369,10 +369,11 @@ namespace osu.Game.Screens.Play var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable; storyboardContainer? - .FadeColour(OsuColour.Gray(Opacity), Duration, Easing.OutQuint) - .FadeTo(storyboardVisible && Opacity > 0 ? 1 : 0, Duration, Easing.OutQuint); + .FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint) + .FadeTo(storyboardVisible && BackgroundOpacity > 0 ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint); - Background?.FadeTo(!storyboardVisible || beatmap.Background == null ? Opacity : 0, Duration, Easing.OutQuint); + if (storyboardVisible && beatmap.Storyboard.ReplacesBackground) + Background?.FadeTo(0, BACKGROUND_FADE_DURATION, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index fa5ed6365f..042b4fc744 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -263,13 +263,5 @@ namespace osu.Game.Screens.Play }; } } - - protected override void UpdateBackgroundElements() - { - if (!IsCurrentScreen) return; - - base.UpdateBackgroundElements(); - Background?.FadeTo(Opacity, Duration, Easing.OutQuint); - } } } diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index 83346d677c..d83f7e087d 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -13,10 +13,12 @@ namespace osu.Game.Screens.Play public abstract class ScreenWithBeatmapBackground : OsuScreen { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap); + public override bool AllowBeatmapRulesetChange => false; - protected float Duration => 800; - protected float Opacity => 1 - (float)DimLevel; + protected const float BACKGROUND_FADE_DURATION = 800; + + protected float BackgroundOpacity => 1 - (float)DimLevel; #region User Settings @@ -52,7 +54,8 @@ namespace osu.Game.Screens.Play { if (!IsCurrentScreen) return; - (Background as BackgroundScreenBeatmap)?.BlurTo(new Vector2((float)BlurLevel.Value * 25), Duration, Easing.OutQuint); + Background?.FadeTo(BackgroundOpacity, BACKGROUND_FADE_DURATION, Easing.OutQuint); + (Background as BackgroundScreenBeatmap)?.BlurTo(new Vector2((float)BlurLevel.Value * 25), BACKGROUND_FADE_DURATION, Easing.OutQuint); } } } From 31cf00e3b83f04aee8c2d28325239f0b1060431d Mon Sep 17 00:00:00 2001 From: Poyo Date: Sun, 25 Feb 2018 23:52:38 -0800 Subject: [PATCH 06/58] Implement mania star difficulty calculation --- .../ManiaDifficultyCalculator.cs | 124 +++++++++++++++++- .../Objects/ManiaHitObjectDifficulty.cs | 114 ++++++++++++++++ .../osu.Game.Rulesets.Mania.csproj | 1 + 3 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index 75a8543548..62d2929f27 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -4,18 +4,140 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; +using System; using System.Collections.Generic; namespace osu.Game.Rulesets.Mania { public class ManiaDifficultyCalculator : DifficultyCalculator { + private const double star_scaling_factor = 0.018; + + /// + /// 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 = 400; + + /// + /// The weighting of each strain value decays to this number * it's previous value + /// + protected const double decay_weight = 0.9; + + /// + /// HitObjects are stored as a member variable. + /// + private readonly List difficultyHitObjects = new List(); + public ManiaDifficultyCalculator(Beatmap beatmap) : base(beatmap) { } - public override double Calculate(Dictionary categoryDifficulty = null) => 0; + public override double Calculate(Dictionary categoryDifficulty = null) + { + // Fill our custom DifficultyHitObject class, that carries additional information + difficultyHitObjects.Clear(); + + int columnCount = (Beatmap as ManiaBeatmap).TotalColumns; + + foreach (var hitObject in Beatmap.HitObjects) + difficultyHitObjects.Add(new ManiaHitObjectDifficulty(hitObject, columnCount)); + + // 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; + + double starRating = calculateDifficulty() * star_scaling_factor; + + if (categoryDifficulty != null) + { + categoryDifficulty.Add("Strain", starRating); + // categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate); + } + + return starRating; + } + + private 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; + + ManiaHitObjectDifficulty current = hitObjectsEnumerator.Current; + + // 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()) + { + var next = hitObjectsEnumerator.Current; + next?.CalculateStrains(current, TimeRate); + current = next; + } + + return true; + } + } + + private double calculateDifficulty() + { + 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 + + ManiaHitObjectDifficulty previousHitObject = null; + foreach (var 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 individualDecay = Math.Pow(ManiaHitObjectDifficulty.INDIVIDUAL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + double overallDecay = Math.Pow(ManiaHitObjectDifficulty.OVERALL_DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000); + maximumStrain = previousHitObject.IndividualStrain * individualDecay + previousHitObject.OverallStrain * overallDecay; + } + + // Go to the next time interval + intervalEndTime += actualStrainStep; + } + + // Obtain maximum strain + double strain = hitObject.IndividualStrain + hitObject.OverallStrain; + maximumStrain = Math.Max(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; + } protected override BeatmapConverter CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, beatmap); } diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs new file mode 100644 index 0000000000..e8b47092f6 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs @@ -0,0 +1,114 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Objects.Types; +using System; + +namespace osu.Game.Rulesets.Mania.Objects +{ + class ManiaHitObjectDifficulty + { + /// + /// Factor by how much individual / overall strain decays per second. + /// + /// + /// These values are results of tweaking a lot and taking into account general feedback. + /// + internal const double INDIVIDUAL_DECAY_BASE = 0.125; + internal const double OVERALL_DECAY_BASE = 0.30; + + internal ManiaHitObject BaseHitObject; + + private int beatmapColumnCount; + + + private double endTime; + private double[] heldUntil; + + /// + /// Measures jacks or more generally: repeated presses of the same button + /// + private double[] individualStrains; + + internal double IndividualStrain + { + get + { + return individualStrains[BaseHitObject.Column]; + } + + set + { + individualStrains[BaseHitObject.Column] = value; + } + } + + /// + /// Measures note density in a way + /// + internal double OverallStrain = 1; + + public ManiaHitObjectDifficulty(ManiaHitObject baseHitObject, int columnCount) + { + BaseHitObject = baseHitObject; + + endTime = (baseHitObject as IHasEndTime)?.EndTime ?? baseHitObject.StartTime; + + beatmapColumnCount = columnCount; + heldUntil = new double[beatmapColumnCount]; + individualStrains = new double[beatmapColumnCount]; + + for (int i = 0; i < beatmapColumnCount; ++i) + { + individualStrains[i] = 0; + heldUntil[i] = 0; + } + } + + internal void CalculateStrains(ManiaHitObjectDifficulty previousHitObject, double timeRate) + { + // TODO: Factor in holds + double addition = 1.0; + double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; + double individualDecay = Math.Pow(INDIVIDUAL_DECAY_BASE, timeElapsed / 1000); + double overallDecay = Math.Pow(OVERALL_DECAY_BASE, timeElapsed / 1000); + + double holdFactor = 1.0; // Factor to all additional strains in case something else is held + double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly + + // Fill up the heldUntil array + for (int i = 0; i < beatmapColumnCount; ++i) + { + heldUntil[i] = previousHitObject.heldUntil[i]; + + // If there is at least one other overlapping end or note, then we get an addition, buuuuuut... + if (BaseHitObject.StartTime < heldUntil[i] && endTime > heldUntil[i]) + { + holdAddition = 1.0; + } + + // ... this addition only is valid if there is _no_ other note with the same ending. Releasing multiple notes at the same time is just as easy as releasing 1 + if (endTime == heldUntil[i]) + { + holdAddition = 0; + } + + // We give a slight bonus to everything if something is held meanwhile + if (heldUntil[i] > endTime) + { + holdFactor = 1.25; + } + + // Decay individual strains + individualStrains[i] = previousHitObject.individualStrains[i] * individualDecay; + } + + heldUntil[BaseHitObject.Column] = endTime; + + // Increase individual strain in own column + IndividualStrain += (2.0/* + (double)SpeedMania.Column / 8.0*/) * holdFactor; + + OverallStrain = previousHitObject.OverallStrain * overallDecay + (addition + holdAddition) * holdFactor; + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index a2e21e2053..b9c62cf40b 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -114,6 +114,7 @@ + From 96f416fef382bad61da66454de0f8f688ae75d27 Mon Sep 17 00:00:00 2001 From: Poyo Date: Mon, 26 Feb 2018 00:18:54 -0800 Subject: [PATCH 07/58] Update code style Sorry, bot overlords. --- osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs | 8 ++++---- .../Objects/ManiaHitObjectDifficulty.cs | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index 62d2929f27..e1d3b6212f 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; namespace osu.Game.Rulesets.Mania { - public class ManiaDifficultyCalculator : DifficultyCalculator + internal class ManiaDifficultyCalculator : DifficultyCalculator { private const double star_scaling_factor = 0.018; @@ -18,12 +18,12 @@ namespace osu.Game.Rulesets.Mania /// 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 = 400; + private const double strain_step = 400; /// /// The weighting of each strain value decays to this number * it's previous value /// - protected const double decay_weight = 0.9; + private const double decay_weight = 0.9; /// /// HitObjects are stored as a member variable. @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania // Fill our custom DifficultyHitObject class, that carries additional information difficultyHitObjects.Clear(); - int columnCount = (Beatmap as ManiaBeatmap).TotalColumns; + int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7; foreach (var hitObject in Beatmap.HitObjects) difficultyHitObjects.Add(new ManiaHitObjectDifficulty(hitObject, columnCount)); diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs index e8b47092f6..0b5e7d7e4c 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs @@ -6,7 +6,7 @@ using System; namespace osu.Game.Rulesets.Mania.Objects { - class ManiaHitObjectDifficulty + internal class ManiaHitObjectDifficulty { /// /// Factor by how much individual / overall strain decays per second. @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Objects internal ManiaHitObject BaseHitObject; - private int beatmapColumnCount; + private readonly int beatmapColumnCount; private double endTime; @@ -68,7 +68,6 @@ namespace osu.Game.Rulesets.Mania.Objects internal void CalculateStrains(ManiaHitObjectDifficulty previousHitObject, double timeRate) { // TODO: Factor in holds - double addition = 1.0; double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate; double individualDecay = Math.Pow(INDIVIDUAL_DECAY_BASE, timeElapsed / 1000); double overallDecay = Math.Pow(OVERALL_DECAY_BASE, timeElapsed / 1000); @@ -106,9 +105,9 @@ namespace osu.Game.Rulesets.Mania.Objects heldUntil[BaseHitObject.Column] = endTime; // Increase individual strain in own column - IndividualStrain += (2.0/* + (double)SpeedMania.Column / 8.0*/) * holdFactor; + IndividualStrain += 2.0 * holdFactor; - OverallStrain = previousHitObject.OverallStrain * overallDecay + (addition + holdAddition) * holdFactor; + OverallStrain = previousHitObject.OverallStrain * overallDecay + (1.0 + holdAddition) * holdFactor; } } } From fb724ca8a705ac6f093be9c96c7e2f30c41b5a07 Mon Sep 17 00:00:00 2001 From: naoey Date: Wed, 28 Feb 2018 08:32:30 +0530 Subject: [PATCH 08/58] Make song select ensure current beatmap is always playable in the active ruleset. - Add a to TestCasePlaySongSelect testing this scenario --- .../Visual/TestCasePlaySongSelect.cs | 38 ++++++++++++++--- osu.Game/Screens/Select/SongSelect.cs | 41 ++++++++++++++++++- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 13b2be9fdb..a4086ea2cd 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.MathUtils; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Rulesets; using osu.Game.Screens.Select; @@ -53,10 +54,14 @@ namespace osu.Game.Tests.Visual public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; public new BeatmapCarousel Carousel => base.Carousel; + + public void SetRuleset(RulesetInfo ruleset) => Ruleset.Value = ruleset; + + public int? RulesetID => Ruleset.Value.ID; } [BackgroundDependencyLoader] - private void load(OsuGameBase game) + private void load(OsuGameBase game, OsuConfigManager config) { TestSongSelect songSelect = null; @@ -113,6 +118,24 @@ namespace osu.Game.Tests.Visual AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; }); AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; }); AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; }); + + AddWaitStep(5); + + AddStep(@"Set unplayable WorkingBeatmap", () => + { + var testMap = manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID != 0); + songSelect.SetRuleset(rulesets.AvailableRulesets.First()); + game.Beatmap.Value = manager.GetWorkingBeatmap(testMap); + }); + AddAssert(@"WorkingBeatmap changed to playable ruleset", () => songSelect.RulesetID == 0 && game.Beatmap.Value.BeatmapInfo.RulesetID == 0); + AddStep(@"Disallow beatmap conversion", () => + { + config.GetBindable(OsuSetting.ShowConvertedBeatmaps).Value = false; + game.Beatmap.Value = manager.GetWorkingBeatmap(manager.GetAllUsableBeatmapSets().First().Beatmaps.First()); + }); + loadNewSongSelect(); + AddWaitStep(3); + AddAssert(@"Ruleset matches beatmap", () => songSelect.RulesetID == game.Beatmap.Value.BeatmapInfo.RulesetID); } private BeatmapSetInfo createTestBeatmapSet(int i) @@ -134,7 +157,8 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1234 + i, - Ruleset = rulesets.AvailableRulesets.First(), + Ruleset = rulesets.AvailableRulesets.ElementAt(0), + RulesetID = 0, Path = "normal.osu", Version = "Normal", BaseDifficulty = new BeatmapDifficulty @@ -145,8 +169,9 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1235 + i, - Ruleset = rulesets.AvailableRulesets.First(), - Path = "hard.osu", + Ruleset = rulesets.AvailableRulesets.First(r => r.ID != 0), + RulesetID = 1, + Path = "hard.taiko", Version = "Hard", BaseDifficulty = new BeatmapDifficulty { @@ -156,8 +181,9 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1236 + i, - Ruleset = rulesets.AvailableRulesets.First(), - Path = "insane.osu", + Ruleset = rulesets.AvailableRulesets.ElementAt(2), + RulesetID = 2, + Path = "insane.fruits", Version = "Insane", BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index de6847d866..6e1d95d42e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Linq; using System.Threading; using OpenTK; using OpenTK.Input; @@ -9,12 +10,14 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; 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.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Overlays; @@ -63,6 +66,8 @@ namespace osu.Game.Screens.Select private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; + private Bindable rulesetConversionAllowed; + private CancellationTokenSource initialAddSetsTask; private DependencyContainer dependencies; @@ -179,7 +184,7 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours) + private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours, OsuConfigManager config) { dependencies.CacheAs(this); @@ -194,6 +199,8 @@ namespace osu.Game.Screens.Select if (this.beatmaps == null) this.beatmaps = beatmaps; + rulesetConversionAllowed = config.GetBindable(OsuSetting.ShowConvertedBeatmaps); + if (osu != null) Ruleset.BindTo(osu.Ruleset); @@ -217,7 +224,10 @@ namespace osu.Game.Screens.Select Beatmap.ValueChanged += b => { if (IsCurrentScreen) + { Carousel.SelectBeatmap(b?.BeatmapInfo); + ensurePlayableRuleset(); + } }; } @@ -316,6 +326,7 @@ namespace osu.Game.Screens.Select { base.OnEntering(last); + ensurePlayableRuleset(); Content.FadeInFromZero(250); FilterControl.Activate(); } @@ -441,6 +452,34 @@ namespace osu.Game.Screens.Select } } + private void ensurePlayableRuleset() + { + if (Beatmap.IsDefault) + // DummyBeatmap won't be playable anyway + return; + + bool conversionAllowed = rulesetConversionAllowed.Value; + int? currentRuleset = Ruleset.Value.ID; + int beatmapRuleset = Beatmap.Value.BeatmapInfo.RulesetID; + + if (currentRuleset == beatmapRuleset || conversionAllowed && beatmapRuleset == 0) + // Current beatmap is playable, nothing more to do + return; + + // Otherwise, first check if the current beatmapset has any playable beatmaps + BeatmapInfo beatmap = Beatmap.Value.BeatmapSetInfo.Beatmaps?.FirstOrDefault(b => b.RulesetID == currentRuleset || conversionAllowed && b.RulesetID == 0); + + // If it does then update the WorkingBeatmap + if (beatmap != null) + { + Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); + return; + } + + // If it doesn't, then update the current ruleset so that the current beatmap is playable + Ruleset.Value = Beatmap.Value.BeatmapInfo.Ruleset; + } + private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s); private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); From a57dc154f9aa323c6ab367442c417b7bb48363ae Mon Sep 17 00:00:00 2001 From: naoey Date: Sat, 3 Mar 2018 19:54:54 +0530 Subject: [PATCH 09/58] More specific tests. --- .../Visual/TestCasePlaySongSelect.cs | 80 ++++++++++++++++--- osu.Game/Screens/Select/SongSelect.cs | 18 +++-- 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index d895080afe..8532962389 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -60,6 +60,14 @@ namespace osu.Game.Tests.Visual public void SetRuleset(RulesetInfo ruleset) => Ruleset.Value = ruleset; public int? RulesetID => Ruleset.Value.ID; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + // Necessary while running tests because gc is moody and uncollected object interferes with OnEntering test + Beatmap.ValueChanged -= WorkingBeatmapChanged; + } } [BackgroundDependencyLoader] @@ -82,6 +90,7 @@ namespace osu.Game.Tests.Visual { if (deleteMaps) { + // TODO: check why this alone doesn't allow import test to run twice in the same session, probably because the delete op is not saved? manager.Delete(manager.GetAllUsableBeatmapSets()); game.Beatmap.SetDefault(); } @@ -93,6 +102,8 @@ namespace osu.Game.Tests.Visual } Add(songSelect = new TestSongSelect()); + + songSelect?.SetRuleset(rulesets.AvailableRulesets.First()); }); loadNewSongSelect(true); @@ -107,6 +118,36 @@ namespace osu.Game.Tests.Visual { for (int i = 0; i < 100; i += 10) manager.Import(createTestBeatmapSet(i)); + + // also import a set which has a single non - osu ruleset beatmap + manager.Import(new BeatmapSetInfo + { + OnlineBeatmapSetID = 1993, + Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), + Metadata = new BeatmapMetadata + { + OnlineBeatmapSetID = 1993, + // 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), + AuthorString = "Some Guy " + RNG.Next(0, 9), + }, + Beatmaps = new List + { + new BeatmapInfo + { + OnlineBeatmapID = 1994, + Ruleset = rulesets.AvailableRulesets.ElementAt(3), + RulesetID = 3, + Path = "normal.fruits", + Version = "Normal", + BaseDifficulty = new BeatmapDifficulty + { + OverallDifficulty = 3.5f, + } + }, + } + }); }); AddWaitStep(3); @@ -121,23 +162,44 @@ namespace osu.Game.Tests.Visual AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; }); AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; }); - AddWaitStep(5); + // Test that song select sets a playable beatmap while entering + AddStep(@"Remove song select", () => + { + Remove(songSelect); + songSelect.Dispose(); + songSelect = null; + }); + AddStep(@"Set non-osu beatmap", () => game.Beatmap.Value = manager.GetWorkingBeatmap(manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID != 0))); + AddAssert(@"Non-osu beatmap set", () => game.Beatmap.Value.BeatmapInfo.RulesetID != 0); + loadNewSongSelect(); + AddWaitStep(3); + AddAssert(@"osu beatmap set", () => game.Beatmap.Value.BeatmapInfo.RulesetID == 0); - AddStep(@"Set unplayable WorkingBeatmap", () => + // Test that song select changes WorkingBeatmap to be playable in current ruleset when updated externally + AddStep(@"Try set non-osu beatmap", () => { var testMap = manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID != 0); songSelect.SetRuleset(rulesets.AvailableRulesets.First()); game.Beatmap.Value = manager.GetWorkingBeatmap(testMap); }); - AddAssert(@"WorkingBeatmap changed to playable ruleset", () => songSelect.RulesetID == 0 && game.Beatmap.Value.BeatmapInfo.RulesetID == 0); - AddStep(@"Disallow beatmap conversion", () => + AddAssert(@"Beatmap changed to osu", () => songSelect.RulesetID == 0 && game.Beatmap.Value.BeatmapInfo.RulesetID == 0); + + // Test that song select updates WorkingBeatmap when ruleset conversion is disabled + AddStep(@"Disable beatmap conversion", () => config.Set(OsuSetting.ShowConvertedBeatmaps, false)); + AddStep(@"Set osu beatmap taiko rs", () => { - config.GetBindable(OsuSetting.ShowConvertedBeatmaps).Value = false; - game.Beatmap.Value = manager.GetWorkingBeatmap(manager.GetAllUsableBeatmapSets().First().Beatmaps.First()); + game.Beatmap.Value = manager.GetWorkingBeatmap(manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID == 0)); + songSelect.SetRuleset(rulesets.AvailableRulesets.First(r => r.ID == 1)); }); - loadNewSongSelect(); - AddWaitStep(3); - AddAssert(@"Ruleset matches beatmap", () => songSelect.RulesetID == game.Beatmap.Value.BeatmapInfo.RulesetID); + AddAssert(@"taiko beatmap set", () => songSelect.RulesetID == 1); + + // Test that song select changes the active ruleset when externally set beatmapset has no playable beatmaps + AddStep(@"Set fruits only beatmapset", () => + { + songSelect.SetRuleset(rulesets.AvailableRulesets.First()); + game.Beatmap.Value = manager.GetWorkingBeatmap(manager.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 1993).Beatmaps.First()); + }); + AddAssert(@"Ruleset changed to fruits", () => songSelect.RulesetID == game.Beatmap.Value.BeatmapInfo.RulesetID); } private BeatmapSetInfo createTestBeatmapSet(int i) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 8033f8da8b..d4fd64dcd9 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -221,14 +221,7 @@ namespace osu.Game.Screens.Select Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.TriggerChange(); - Beatmap.ValueChanged += b => - { - if (IsCurrentScreen) - { - Carousel.SelectBeatmap(b?.BeatmapInfo); - ensurePlayableRuleset(); - } - }; + Beatmap.ValueChanged += WorkingBeatmapChanged; } public void Edit(BeatmapInfo beatmap) @@ -271,6 +264,15 @@ namespace osu.Game.Screens.Select // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. private BeatmapInfo beatmapNoDebounce; + protected void WorkingBeatmapChanged(WorkingBeatmap beatmap) + { + if (IsCurrentScreen) + { + Carousel.SelectBeatmap(beatmap?.BeatmapInfo); + ensurePlayableRuleset(); + } + } + /// /// selection has been changed as the result of interaction with the carousel. /// From c6c55c40edf51afef87b5b1531e7da02ebccdfaa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 4 Mar 2018 00:50:41 +0900 Subject: [PATCH 10/58] Rewrite BreakOverlay No longer relies on Schedule calls (could not be rewound). Also no longer sucks. --- osu.Game.Tests/Visual/TestCaseBreakOverlay.cs | 2 +- .../{BreaksOverlay => Break}/BlurredIcon.cs | 10 +- .../ArrowsOverlay.cs => Break/BreakArrows.cs} | 35 ++--- .../InfoContainer.cs => Break/BreakInfo.cs} | 26 ++-- .../InfoLine.cs => Break/BreakInfoLine.cs} | 10 +- .../Play/{BreaksOverlay => Break}/GlowIcon.cs | 12 +- .../LetterboxOverlay.cs | 13 +- .../RemainingTimeCounter.cs | 14 +- .../Play/{BreaksOverlay => }/BreakOverlay.cs | 142 +++++++++--------- osu.Game/Screens/Play/Player.cs | 1 - osu.Game/osu.Game.csproj | 16 +- 11 files changed, 125 insertions(+), 156 deletions(-) rename osu.Game/Screens/Play/{BreaksOverlay => Break}/BlurredIcon.cs (92%) rename osu.Game/Screens/Play/{BreaksOverlay/ArrowsOverlay.cs => Break/BreakArrows.cs} (78%) rename osu.Game/Screens/Play/{BreaksOverlay/InfoContainer.cs => Break/BreakInfo.cs} (62%) rename osu.Game/Screens/Play/{BreaksOverlay/InfoLine.cs => Break/BreakInfoLine.cs} (84%) rename osu.Game/Screens/Play/{BreaksOverlay => Break}/GlowIcon.cs (93%) rename osu.Game/Screens/Play/{BreaksOverlay => Break}/LetterboxOverlay.cs (77%) rename osu.Game/Screens/Play/{BreaksOverlay => Break}/RemainingTimeCounter.cs (70%) rename osu.Game/Screens/Play/{BreaksOverlay => }/BreakOverlay.cs (51%) diff --git a/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs index ae24d86325..51b8c61963 100644 --- a/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs +++ b/osu.Game.Tests/Visual/TestCaseBreakOverlay.cs @@ -3,9 +3,9 @@ using osu.Framework.Timing; using osu.Game.Beatmaps.Timing; -using osu.Game.Screens.Play.BreaksOverlay; using System.Collections.Generic; using NUnit.Framework; +using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual { diff --git a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs b/osu.Game/Screens/Play/Break/BlurredIcon.cs similarity index 92% rename from osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs rename to osu.Game/Screens/Play/Break/BlurredIcon.cs index 5395d7688e..6f47c97f89 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BlurredIcon.cs +++ b/osu.Game/Screens/Play/Break/BlurredIcon.cs @@ -1,13 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Game.Graphics; using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using OpenTK; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { public class BlurredIcon : BufferedContainer { diff --git a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs b/osu.Game/Screens/Play/Break/BreakArrows.cs similarity index 78% rename from osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs rename to osu.Game/Screens/Play/Break/BreakArrows.cs index 9fdf90bd28..f2a60cdddf 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/ArrowsOverlay.cs +++ b/osu.Game/Screens/Play/Break/BreakArrows.cs @@ -1,18 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; -using OpenTK; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -using osu.Game.Beatmaps.Timing; +using OpenTK; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class ArrowsOverlay : VisibilityContainer + public class BreakArrows : CompositeDrawable { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private const int glow_icon_size = 60; private const int glow_icon_blur_sigma = 10; private const float glow_icon_final_offset = 0.22f; @@ -29,10 +26,10 @@ namespace osu.Game.Screens.Play.BreaksOverlay private readonly BlurredIcon leftBlurredIcon; private readonly BlurredIcon rightBlurredIcon; - public ArrowsOverlay() + public BreakArrows() { RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + InternalChildren = new Drawable[] { leftGlowIcon = new GlowIcon { @@ -82,22 +79,22 @@ namespace osu.Game.Screens.Play.BreaksOverlay }; } - protected override void PopIn() + public void Show(double duration) { - leftGlowIcon.MoveToX(-glow_icon_final_offset, fade_duration, Easing.OutQuint); - rightGlowIcon.MoveToX(glow_icon_final_offset, fade_duration, Easing.OutQuint); + leftGlowIcon.MoveToX(-glow_icon_final_offset, duration, Easing.OutQuint); + rightGlowIcon.MoveToX(glow_icon_final_offset, duration, Easing.OutQuint); - leftBlurredIcon.MoveToX(-blurred_icon_final_offset, fade_duration, Easing.OutQuint); - rightBlurredIcon.MoveToX(blurred_icon_final_offset, fade_duration, Easing.OutQuint); + leftBlurredIcon.MoveToX(-blurred_icon_final_offset, duration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_icon_final_offset, duration, Easing.OutQuint); } - protected override void PopOut() + public void Hide(double duration) { - leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, fade_duration, Easing.OutQuint); - rightGlowIcon.MoveToX(glow_icon_offscreen_offset, fade_duration, Easing.OutQuint); + leftGlowIcon.MoveToX(-glow_icon_offscreen_offset, duration, Easing.OutQuint); + rightGlowIcon.MoveToX(glow_icon_offscreen_offset, duration, Easing.OutQuint); - leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint); - rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, fade_duration, Easing.OutQuint); + leftBlurredIcon.MoveToX(-blurred_icon_offscreen_offset, duration, Easing.OutQuint); + rightBlurredIcon.MoveToX(blurred_icon_offscreen_offset, duration, Easing.OutQuint); } } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs b/osu.Game/Screens/Play/Break/BreakInfo.cs similarity index 62% rename from osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs rename to osu.Game/Screens/Play/Break/BreakInfo.cs index d7ab4ff2e5..5e011903fe 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoContainer.cs +++ b/osu.Game/Screens/Play/Break/BreakInfo.cs @@ -1,24 +1,21 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; -using osu.Game.Beatmaps.Timing; +using OpenTK; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class InfoContainer : VisibilityContainer + public class BreakInfo : Container { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; + public PercentageBreakInfoLine AccuracyDisplay; + public BreakInfoLine RankDisplay; + public BreakInfoLine GradeDisplay; - public PercentageInfoLine AccuracyDisplay; - public InfoLine RankDisplay; - public InfoLine GradeDisplay; - - public InfoContainer() + public BreakInfo() { AutoSizeAxes = Axes.Both; Child = new FillFlowContainer @@ -43,16 +40,13 @@ namespace osu.Game.Screens.Play.BreaksOverlay Direction = FillDirection.Vertical, Children = new Drawable[] { - AccuracyDisplay = new PercentageInfoLine("Accuracy"), - RankDisplay = new InfoLine("Rank"), - GradeDisplay = new InfoLine("Grade"), + AccuracyDisplay = new PercentageBreakInfoLine("Accuracy"), + RankDisplay = new BreakInfoLine("Rank"), + GradeDisplay = new BreakInfoLine("Grade"), }, } }, }; } - - protected override void PopIn() => this.FadeIn(fade_duration); - protected override void PopOut() => this.FadeOut(fade_duration); } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs b/osu.Game/Screens/Play/Break/BreakInfoLine.cs similarity index 84% rename from osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs rename to osu.Game/Screens/Play/Break/BreakInfoLine.cs index b39eaf1c22..3d96bca1fa 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/InfoLine.cs +++ b/osu.Game/Screens/Play/Break/BreakInfoLine.cs @@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class InfoLine : Container + public class BreakInfoLine : Container where T : struct { private const int margin = 2; @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay private readonly string prefix; - public InfoLine(string name, string prefix = @"") + public BreakInfoLine(string name, string prefix = @"") { this.prefix = prefix; @@ -71,9 +71,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay } } - public class PercentageInfoLine : InfoLine + public class PercentageBreakInfoLine : BreakInfoLine { - public PercentageInfoLine(string name, string prefix = "") : base(name, prefix) + public PercentageBreakInfoLine(string name, string prefix = "") : base(name, prefix) { } diff --git a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs b/osu.Game/Screens/Play/Break/GlowIcon.cs similarity index 93% rename from osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs rename to osu.Game/Screens/Play/Break/GlowIcon.cs index bad9df2093..79b39a873a 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/GlowIcon.cs +++ b/osu.Game/Screens/Play/Break/GlowIcon.cs @@ -1,13 +1,13 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Graphics.Containers; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using OpenTK; -using osu.Framework.Allocation; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { public class GlowIcon : Container { @@ -16,24 +16,24 @@ namespace osu.Game.Screens.Play.BreaksOverlay public override Vector2 Size { + get { return base.Size; } set { blurredIcon.Size = spriteIcon.Size = value; blurredIcon.ForceRedraw(); } - get { return base.Size; } } public Vector2 BlurSigma { - set { blurredIcon.BlurSigma = value; } get { return blurredIcon.BlurSigma; } + set { blurredIcon.BlurSigma = value; } } public FontAwesome Icon { - set { spriteIcon.Icon = blurredIcon.Icon = value; } get { return spriteIcon.Icon; } + set { spriteIcon.Icon = blurredIcon.Icon = value; } } public GlowIcon() diff --git a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs similarity index 77% rename from osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs rename to osu.Game/Screens/Play/Break/LetterboxOverlay.cs index f4c9362fff..21eb5ebea0 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs @@ -1,18 +1,16 @@ // 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.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Beatmaps.Timing; +using OpenTK.Graphics; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { - public class LetterboxOverlay : VisibilityContainer + public class LetterboxOverlay : CompositeDrawable { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; private const int height = 350; private static readonly Color4 transparent_black = new Color4(0, 0, 0, 0); @@ -20,7 +18,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay public LetterboxOverlay() { RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + InternalChildren = new Drawable[] { new Container { @@ -48,8 +46,5 @@ namespace osu.Game.Screens.Play.BreaksOverlay } }; } - - protected override void PopIn() => this.FadeIn(fade_duration); - protected override void PopOut() => this.FadeOut(fade_duration); } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs b/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs similarity index 70% rename from osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs rename to osu.Game/Screens/Play/Break/RemainingTimeCounter.cs index 015fefb423..f6e683f519 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs @@ -1,18 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Graphics.Sprites; -using osu.Framework.Graphics; using System; -using osu.Game.Beatmaps.Timing; +using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Sprites; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play.Break { public class RemainingTimeCounter : Counter { - private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; - private readonly OsuSpriteText counter; public RemainingTimeCounter() @@ -25,13 +22,8 @@ namespace osu.Game.Screens.Play.BreaksOverlay TextSize = 33, Font = "Venera", }; - - Alpha = 0; } protected override void OnCountChanged(double count) => counter.Text = ((int)Math.Ceiling(count / 1000)).ToString(); - - public override void Show() => this.FadeIn(fade_duration); - public override void Hide() => this.FadeOut(fade_duration); } } diff --git a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs similarity index 51% rename from osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs rename to osu.Game/Screens/Play/BreakOverlay.cs index af7c1ef5aa..6c7ee596a1 100644 --- a/osu.Game/Screens/Play/BreaksOverlay/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -1,15 +1,16 @@ // 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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Scoring; -using System.Collections.Generic; -using osu.Framework.Graphics.UserInterface; +using osu.Game.Screens.Play.Break; -namespace osu.Game.Screens.Play.BreaksOverlay +namespace osu.Game.Screens.Play { public class BreakOverlay : Container { @@ -18,28 +19,26 @@ namespace osu.Game.Screens.Play.BreaksOverlay private const int vertical_margin = 25; private List breaks; + + private readonly Container fadeContainer; + public List Breaks { + get => breaks; set { breaks = value; initializeBreaks(); } - get - { - return breaks; - } } public override bool RemoveCompletedTransforms => false; - private readonly bool letterboxing; - private readonly LetterboxOverlay letterboxOverlay; private readonly Container remainingTimeAdjustmentBox; private readonly Container remainingTimeBox; private readonly RemainingTimeCounter remainingTimeCounter; - private readonly InfoContainer info; - private readonly ArrowsOverlay arrowsOverlay; + private readonly BreakInfo info; + private readonly BreakArrows breakArrows; public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor) : this(letterboxing) @@ -49,61 +48,72 @@ namespace osu.Game.Screens.Play.BreaksOverlay public BreakOverlay(bool letterboxing) { - this.letterboxing = letterboxing; - RelativeSizeAxes = Axes.Both; - Children = new Drawable[] + Child = fadeContainer = new Container { - letterboxOverlay = new LetterboxOverlay + Alpha = 0, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - remainingTimeAdjustmentBox = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Width = 0, - Child = remainingTimeBox = new Container + new LetterboxOverlay + { + Alpha = letterboxing ? 1 : 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + remainingTimeAdjustmentBox = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, - Height = 8, - CornerRadius = 4, - Masking = true, - Child = new Box { RelativeSizeAxes = Axes.Both } + Width = 0, + Child = remainingTimeBox = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = 8, + CornerRadius = 4, + Masking = true, + Child = new Box { RelativeSizeAxes = Axes.Both } + } + }, + remainingTimeCounter = new RemainingTimeCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Margin = new MarginPadding { Bottom = vertical_margin }, + }, + info = new BreakInfo + { + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Margin = new MarginPadding { Top = vertical_margin }, + }, + breakArrows = new BreakArrows + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, } - }, - remainingTimeCounter = new RemainingTimeCounter - { - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - Margin = new MarginPadding { Bottom = vertical_margin }, - }, - info = new InfoContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = vertical_margin }, - }, - arrowsOverlay = new ArrowsOverlay - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, } }; } + protected override void LoadComplete() + { + base.LoadComplete(); + initializeBreaks(); + } + private void initializeBreaks() { + if (!IsLoaded) return; // we need a clock. + FinishTransforms(true); Scheduler.CancelDelayedTasks(); - if (breaks == null) - return; + if (breaks == null) return; //we need breaks. foreach (var b in breaks) { @@ -112,6 +122,9 @@ namespace osu.Game.Screens.Play.BreaksOverlay using (BeginAbsoluteSequence(b.StartTime, true)) { + fadeContainer.FadeIn(fade_duration); + breakArrows.Show(fade_duration); + remainingTimeAdjustmentBox .ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) .Delay(b.Duration - fade_duration) @@ -123,37 +136,16 @@ namespace osu.Game.Screens.Play.BreaksOverlay .ResizeWidthTo(1); remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration); - } - using (BeginAbsoluteSequence(b.StartTime)) - { - Schedule(showBreak); - using (BeginDelayedSequence(b.Duration - fade_duration)) - Schedule(hideBreak); + using (BeginDelayedSequence(b.Duration - fade_duration, true)) + { + fadeContainer.FadeOut(fade_duration); + breakArrows.Hide(fade_duration); + } } } } - private void showBreak() - { - if (letterboxing) - letterboxOverlay.Show(); - - remainingTimeCounter.Show(); - info.Show(); - arrowsOverlay.Show(); - } - - private void hideBreak() - { - if (letterboxing) - letterboxOverlay.Hide(); - - remainingTimeCounter.Hide(); - info.Hide(); - arrowsOverlay.Hide(); - } - private void bindProcessor(ScoreProcessor processor) { info.AccuracyDisplay.Current.BindTo(processor.Accuracy); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7a0c723ab5..84f6cd606a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -26,7 +26,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Backgrounds; -using osu.Game.Screens.Play.BreaksOverlay; using osu.Game.Screens.Ranking; using osu.Game.Storyboards.Drawables; using OpenTK; diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ff365ad93e..429e7c7b27 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -395,14 +395,14 @@ - - - - - - - - + + + + + + + + From e187c6453d841aa393dda610938e858b786951bf Mon Sep 17 00:00:00 2001 From: Poyo Date: Mon, 5 Mar 2018 18:19:06 -0800 Subject: [PATCH 11/58] Added mania-difficulty mod support --- .../ManiaDifficultyCalculator.cs | 15 ++++++++------- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Objects/ManiaHitObjectDifficulty.cs | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index e1d3b6212f..02560c8141 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -4,6 +4,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mods; using System; using System.Collections.Generic; @@ -31,8 +32,11 @@ namespace osu.Game.Rulesets.Mania private readonly List difficultyHitObjects = new List(); public ManiaDifficultyCalculator(Beatmap beatmap) - : base(beatmap) - { + : base(beatmap) { + } + + public ManiaDifficultyCalculator(Beatmap beatmap, Mod[] mods) + : base(beatmap, mods) { } public override double Calculate(Dictionary categoryDifficulty = null) @@ -53,11 +57,8 @@ namespace osu.Game.Rulesets.Mania double starRating = calculateDifficulty() * star_scaling_factor; - if (categoryDifficulty != null) - { - categoryDifficulty.Add("Strain", starRating); - // categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate); - } + categoryDifficulty?.Add("Strain", starRating); + // categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate); return starRating; } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 3bfb4d3e44..ac815e0e2f 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Mania public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; - public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap); + public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new ManiaDifficultyCalculator(beatmap, mods); public override int LegacyID => 3; diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs index 0b5e7d7e4c..2b59279972 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs @@ -22,13 +22,13 @@ namespace osu.Game.Rulesets.Mania.Objects private readonly int beatmapColumnCount; - private double endTime; - private double[] heldUntil; + private readonly double endTime; + private readonly double[] heldUntil; /// /// Measures jacks or more generally: repeated presses of the same button /// - private double[] individualStrains; + private readonly double[] individualStrains; internal double IndividualStrain { From bd952ce370453f7e63ae18153dc56f9098db5c7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Mar 2018 18:20:20 +0900 Subject: [PATCH 12/58] Allow skinnable drawables to be of non-restricted size --- osu.Game/Skinning/LegacySkin.cs | 10 +++------ osu.Game/Skinning/SkinnableDrawable.cs | 29 ++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 17fe6369a7..f03d1ce632 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -32,12 +32,7 @@ namespace osu.Game.Skinning var texture = textures.Get(componentName); if (texture == null) return null; - return new Sprite - { - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Texture = texture, - }; + return new Sprite { Texture = texture }; } public override SampleChannel GetSample(string sampleName) => samples.Get(sampleName); @@ -48,7 +43,8 @@ namespace osu.Game.Skinning private readonly IResourceStore underlyingStore; private string getPathForFile(string filename) => - skin.Files.FirstOrDefault(f => string.Equals(Path.GetFileNameWithoutExtension(f.Filename), filename.Split('/').Last(), StringComparison.InvariantCultureIgnoreCase))?.FileInfo.StoragePath; + skin.Files.FirstOrDefault(f => string.Equals(Path.GetFileNameWithoutExtension(f.Filename), filename.Split('/').Last(), StringComparison.InvariantCultureIgnoreCase))?.FileInfo + .StoragePath; public LegacySkinResourceStore(SkinInfo skin, IResourceStore underlyingStore) { diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index cd669778a6..a5f22f60a2 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -3,13 +3,14 @@ using System; using osu.Framework.Graphics; +using OpenTK; namespace osu.Game.Skinning { public class SkinnableDrawable : SkinnableDrawable { - public SkinnableDrawable(string name, Func defaultImplementation, bool fallback = true) - : base(name, defaultImplementation, fallback) + public SkinnableDrawable(string name, Func defaultImplementation, bool fallback = true, bool restrictSize = true) + : base(name, defaultImplementation, fallback, restrictSize) { } } @@ -21,10 +22,16 @@ namespace osu.Game.Skinning private readonly string componentName; - public SkinnableDrawable(string name, Func defaultImplementation, bool fallback = true) : base(fallback) + /// + /// Whether a user-skin drawable should be limited to the size of our parent. + /// + public readonly bool RestrictSize; + + public SkinnableDrawable(string name, Func defaultImplementation, bool fallback = true, bool restrictSize = true) : base(fallback) { componentName = name; createDefault = defaultImplementation; + RestrictSize = restrictSize; RelativeSizeAxes = Axes.Both; } @@ -32,11 +39,25 @@ namespace osu.Game.Skinning protected override void SkinChanged(Skin skin, bool allowFallback) { var drawable = skin.GetDrawableComponent(componentName); - if (drawable == null && allowFallback) + if (drawable != null) + { + if (RestrictSize) + { + drawable.RelativeSizeAxes = Axes.Both; + drawable.Size = Vector2.One; + drawable.FillMode = FillMode.Fit; + } + } + else if (allowFallback) drawable = createDefault(componentName); if (drawable != null) + { + drawable.Origin = Anchor.Centre; + drawable.Anchor = Anchor.Centre; + InternalChild = drawable; + } else ClearInternal(); } From 05eb6786548780dd2231f24c466ba84411de1fa2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Mar 2018 18:20:35 +0900 Subject: [PATCH 13/58] Add skin support for judgements --- .../Objects/Drawables/DrawableOsuJudgement.cs | 2 +- .../Rulesets/Judgements/DrawableJudgement.cs | 42 ++++++++++++------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 716f4b629b..6d6cae9ca5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void LoadComplete() { if (Judgement.Result != HitResult.Miss) - JudgementText.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint); + JudgementText?.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint); base.LoadComplete(); } diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index c1bf55b214..4664517312 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -10,6 +10,8 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; +using OpenTK.Graphics; namespace osu.Game.Rulesets.Judgements { @@ -18,9 +20,11 @@ namespace osu.Game.Rulesets.Judgements /// public class DrawableJudgement : Container { + private const float judgement_size = 80; + protected readonly Judgement Judgement; - protected readonly SpriteText JudgementText; + protected SpriteText JudgementText; /// /// Creates a drawable which visualises a . @@ -30,31 +34,37 @@ namespace osu.Game.Rulesets.Judgements { Judgement = judgement; - AutoSizeAxes = Axes.Both; - - Children = new[] - { - JudgementText = new OsuSpriteText - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Text = judgement.Result.GetDescription().ToUpper(), - Font = @"Venera", - Scale = new Vector2(0.85f, 1), - TextSize = 12 - } - }; + Size = new Vector2(judgement_size); } [BackgroundDependencyLoader] private void load(OsuColour colours) { + string legacyName = string.Empty; switch (Judgement.Result) { case HitResult.Miss: - Colour = colours.Red; + legacyName = "hit0"; + break; + case HitResult.Meh: + legacyName = "hit50"; + break; + case HitResult.Good: + legacyName = "hit100"; + break; + case HitResult.Great: + legacyName = "hit300"; break; } + + Child = new SkinnableDrawable($"Play/osu/{legacyName}", _ => JudgementText = new OsuSpriteText + { + Text = Judgement.Result.GetDescription().ToUpper(), + Font = @"Venera", + Colour = Judgement.Result == HitResult.Miss ? colours.Red : Color4.White, + Scale = new Vector2(0.85f, 1), + TextSize = 12 + }, restrictSize: false); } protected override void LoadComplete() From f2d7621df3a05a662819a4c83c7c5a598f6cff0f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Mar 2018 18:20:52 +0900 Subject: [PATCH 14/58] Add skin support for explode/flash layers Basically to hide them for legacy skins, though. --- .../Objects/Drawables/Pieces/ExplodePiece.cs | 14 ++++++-------- .../Objects/Drawables/Pieces/FlashPiece.cs | 12 ++++++------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs index 9be951e29c..76ed89be67 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ExplodePiece.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Skinning; using OpenTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces @@ -19,15 +20,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Blending = BlendingMode.Additive; Alpha = 0; - Children = new Drawable[] + Child = new SkinnableDrawable("Play/osu/hitcircle-explode", _ => new TrianglesPiece { - new TrianglesPiece - { - Blending = BlendingMode.Additive, - RelativeSizeAxes = Axes.Both, - Alpha = 0.2f, - } - }; + Blending = BlendingMode.Additive, + RelativeSizeAxes = Axes.Both, + Alpha = 0.2f, + }, false); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs index 56faa335b1..921d24f69d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/FlashPiece.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using OpenTK; using osu.Framework.Graphics.Shapes; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { @@ -14,22 +15,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { Size = new Vector2(128); - Masking = true; - CornerRadius = Size.X / 2; - Anchor = Anchor.Centre; Origin = Anchor.Centre; Blending = BlendingMode.Additive; Alpha = 0; - Children = new Drawable[] + Child = new SkinnableDrawable("Play/osu/hitcircle-flash", name => new CircularContainer { - new Box + Masking = true, + RelativeSizeAxes = Axes.Both, + Child = new Box { RelativeSizeAxes = Axes.Both } - }; + }, false); } } } From b62ed004f274b3bf25704d2d8dfb6ebe909a715a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Mar 2018 19:14:42 +0900 Subject: [PATCH 15/58] Remove judgements when deciding a new judgement for a HitObject Generally happens when rewinding. --- .../UI/DrawableManiaJudgement.cs | 5 ++-- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 7 +++--- .../Objects/Drawables/DrawableOsuJudgement.cs | 6 ++--- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 11 ++++----- .../UI/DrawableTaikoJudgement.cs | 7 ++---- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 7 +++--- .../Rulesets/Judgements/DrawableJudgement.cs | 6 ++++- osu.Game/Rulesets/UI/JudgementContainer.cs | 24 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 9 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 osu.Game/Rulesets/UI/JudgementContainer.cs diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 8a03f5a785..b8ae09c4a0 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -3,13 +3,14 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Mania.UI { internal class DrawableManiaJudgement : DrawableJudgement { - public DrawableManiaJudgement(Judgement judgement) - : base(judgement) + public DrawableManiaJudgement(Judgement judgement, DrawableHitObject judgedObject) + : base(judgement, judgedObject) { JudgementText.TextSize = 25; } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index 2b8039f5df..d4ca704829 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; @@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.UI private readonly Container content; public Container Judgements => judgements; - private readonly Container judgements; + private readonly JudgementContainer judgements; private readonly Container topLevelContainer; @@ -114,7 +115,7 @@ namespace osu.Game.Rulesets.Mania.UI Padding = new MarginPadding { Top = HIT_TARGET_POSITION } } }, - judgements = new Container + judgements = new JudgementContainer { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, @@ -171,7 +172,7 @@ namespace osu.Game.Rulesets.Mania.UI internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) { judgements.Clear(); - judgements.Add(new DrawableManiaJudgement(judgement) + judgements.Add(new DrawableManiaJudgement(judgement, judgedObject) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 716f4b629b..0b1df4bdf5 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -2,17 +2,17 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Graphics; -using osu.Game.Rulesets.Osu.Judgements; using OpenTK; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Objects.Drawables { public class DrawableOsuJudgement : DrawableJudgement { - public DrawableOsuJudgement(OsuJudgement judgement) - : base(judgement) + public DrawableOsuJudgement(Judgement judgement, DrawableHitObject judgedObject) + : base(judgement, judgedObject) { } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 7f8cbce78e..98a8096678 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.UI public class OsuPlayfield : Playfield { private readonly Container approachCircles; - private readonly Container judgementLayer; + private readonly JudgementContainer judgementLayer; private readonly ConnectionRenderer connectionLayer; // Todo: This should not be a thing, but is currently required for the editor @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Depth = 2, }, - judgementLayer = new Container + judgementLayer = new JudgementContainer { RelativeSizeAxes = Axes.Both, Depth = 1, @@ -75,16 +75,13 @@ namespace osu.Game.Rulesets.Osu.UI private void onJudgement(DrawableHitObject judgedObject, Judgement judgement) { - var osuJudgement = (OsuJudgement)judgement; - var osuObject = (OsuHitObject)judgedObject.HitObject; - if (!judgedObject.DisplayJudgement) return; - DrawableOsuJudgement explosion = new DrawableOsuJudgement(osuJudgement) + DrawableOsuJudgement explosion = new DrawableOsuJudgement(judgement, judgedObject) { Origin = Anchor.Centre, - Position = osuObject.StackedEndPosition + osuJudgement.PositionOffset + Position = ((OsuHitObject)judgedObject.HitObject).StackedEndPosition + ((OsuJudgement)judgement).PositionOffset }; judgementLayer.Add(explosion); diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index c0e8bd1b5a..6274232ffd 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -15,17 +15,14 @@ namespace osu.Game.Rulesets.Taiko.UI /// public class DrawableTaikoJudgement : DrawableJudgement { - public readonly DrawableHitObject JudgedObject; - /// /// Creates a new judgement text. /// /// The object which is being judged. /// The judgement to visualise. - public DrawableTaikoJudgement(DrawableHitObject judgedObject, Judgement judgement) - : base(judgement) + public DrawableTaikoJudgement(Judgement judgement, DrawableHitObject judgedObject) + : base(judgement, judgedObject) { - JudgedObject = judgedObject; } [BackgroundDependencyLoader] diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 49c87f7480..75aaceaecb 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -16,6 +16,7 @@ using System.Linq; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Taiko.UI @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Container hitExplosionContainer; private readonly Container kiaiExplosionContainer; - private readonly Container judgementContainer; + private readonly JudgementContainer judgementContainer; protected override Container Content => content; private readonly Container content; @@ -131,7 +132,7 @@ namespace osu.Game.Rulesets.Taiko.UI Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, Blending = BlendingMode.Additive }, - judgementContainer = new Container + judgementContainer = new JudgementContainer { Name = "Judgements", RelativeSizeAxes = Axes.Y, @@ -227,7 +228,7 @@ namespace osu.Game.Rulesets.Taiko.UI { if (judgedObject.DisplayJudgement && judgementContainer.FirstOrDefault(j => j.JudgedObject == judgedObject) == null) { - judgementContainer.Add(new DrawableTaikoJudgement(judgedObject, judgement) + judgementContainer.Add(new DrawableTaikoJudgement(judgement, judgedObject) { Anchor = judgement.IsHit ? Anchor.TopLeft : Anchor.CentreLeft, Origin = judgement.IsHit ? Anchor.BottomCentre : Anchor.Centre, diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index c1bf55b214..a3811654f2 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Judgements @@ -20,15 +21,18 @@ namespace osu.Game.Rulesets.Judgements { protected readonly Judgement Judgement; + public readonly DrawableHitObject JudgedObject; + protected readonly SpriteText JudgementText; /// /// Creates a drawable which visualises a . /// /// The judgement to visualise. - public DrawableJudgement(Judgement judgement) + public DrawableJudgement(Judgement judgement, DrawableHitObject judgedObject) { Judgement = judgement; + JudgedObject = judgedObject; AutoSizeAxes = Axes.Both; diff --git a/osu.Game/Rulesets/UI/JudgementContainer.cs b/osu.Game/Rulesets/UI/JudgementContainer.cs new file mode 100644 index 0000000000..1291b9fc98 --- /dev/null +++ b/osu.Game/Rulesets/UI/JudgementContainer.cs @@ -0,0 +1,24 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Judgements; + +namespace osu.Game.Rulesets.UI +{ + public class JudgementContainer : Container + where T : DrawableJudgement + { + public override void Add(T judgement) + { + if (judgement == null) throw new ArgumentNullException(nameof(judgement)); + + // remove any existing judgements for the judged object. + // this can be the case when rewinding. + RemoveAll(c => c.JudgedObject == judgement.JudgedObject); + + base.Add(judgement); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b8ada7c017..2a72023e74 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -374,6 +374,7 @@ + From fe3ab94afbfc84665e28fa8df731a507d6a3656c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Mar 2018 19:19:56 +0900 Subject: [PATCH 16/58] Fix mania judgement regression --- osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 8a03f5a785..ab3c5bcbb8 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.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.Framework.Graphics; using osu.Game.Rulesets.Judgements; @@ -11,7 +12,13 @@ namespace osu.Game.Rulesets.Mania.UI public DrawableManiaJudgement(Judgement judgement) : base(judgement) { - JudgementText.TextSize = 25; + } + + [BackgroundDependencyLoader] + private void load() + { + if (JudgementText != null) + JudgementText.TextSize = 25; } protected override void LoadComplete() From ee96e974a89b81d22d12ce86560d4bf02097819d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Mar 2018 09:43:31 +0900 Subject: [PATCH 17/58] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 6372fb22c1..865b0df18b 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 6372fb22c1c85f600921a139849b8dedf71026d5 +Subproject commit 865b0df18bb240190cdf7a7f60d44c0b28c84c5f From 3b5699911808e7796de3dc40d9d556e097d4e665 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Mar 2018 12:57:12 +0900 Subject: [PATCH 18/58] Add drawable to display (and update) relative dates --- osu.Game/Graphics/DrawableDate.cs | 64 +++++++++++++++++++ osu.Game/Overlays/Profile/ProfileHeader.cs | 59 ++++++++--------- .../Sections/Ranks/DrawableProfileScore.cs | 7 +- .../Sections/Recent/DrawableRecentActivity.cs | 9 +-- osu.Game/osu.Game.csproj | 1 + 5 files changed, 95 insertions(+), 45 deletions(-) create mode 100644 osu.Game/Graphics/DrawableDate.cs diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs new file mode 100644 index 0000000000..452443f9d0 --- /dev/null +++ b/osu.Game/Graphics/DrawableDate.cs @@ -0,0 +1,64 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Threading; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Graphics +{ + public class DrawableDate : OsuSpriteText, IHasTooltip + { + private readonly DateTimeOffset date; + private ScheduledDelegate updateTask; + + public DrawableDate(DateTimeOffset date) + { + AutoSizeAxes = Axes.Both; + Font = "Exo2.0-RegularItalic"; + + this.date = date.ToLocalTime(); + } + + [BackgroundDependencyLoader] + private void load() + { + updateTime(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.Add(updateTimeWithReschedule); + } + + private void updateTimeWithReschedule() + { + updateTime(); + + var diffToNow = DateTimeOffset.Now.Subtract(date); + + double timeUntilNextUpdate = 1000; + if (diffToNow.TotalSeconds > 60) + { + timeUntilNextUpdate *= 60; + if (diffToNow.TotalMinutes > 60) + { + timeUntilNextUpdate *= 60; + + if (diffToNow.TotalHours > 24) + timeUntilNextUpdate *= 24; + } + } + + Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate); + } + + private void updateTime() => Text = date.Humanize(); + public string TooltipText => date.ToString(); + } +} diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index d085800f41..f4b363cd91 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -130,11 +130,7 @@ namespace osu.Game.Overlays.Profile } } }, - infoTextLeft = new OsuTextFlowContainer(t => - { - t.TextSize = 14; - t.Alpha = 0.8f; - }) + infoTextLeft = new OsuTextFlowContainer(t => t.TextSize = 14) { X = UserProfileOverlay.CONTENT_X_MARGIN, Y = cover_height + 20, @@ -318,11 +314,23 @@ namespace osu.Game.Overlays.Profile colourBar.Show(); } - void boldItalic(SpriteText t) + void boldItalic(SpriteText t) => t.Font = @"Exo2.0-BoldItalic"; + void lightText(SpriteText t) => t.Alpha = 0.8f; + + OsuSpriteText createScoreText(string text) => new OsuSpriteText { - t.Font = @"Exo2.0-BoldItalic"; - t.Alpha = 1; - } + TextSize = 14, + Text = text + }; + + OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText + { + TextSize = 14, + Font = @"Exo2.0-Bold", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Text = text + }; if (user.Age != null) { @@ -331,7 +339,7 @@ namespace osu.Game.Overlays.Profile if (user.Country != null) { - infoTextLeft.AddText("from "); + infoTextLeft.AddText("from ", lightText); infoTextLeft.AddText(user.Country.FullName, boldItalic); countryFlag.Country = user.Country; } @@ -344,18 +352,18 @@ namespace osu.Game.Overlays.Profile } else { - infoTextLeft.AddText("Joined "); - infoTextLeft.AddText(user.JoinDate.LocalDateTime.ToShortDateString(), boldItalic); + infoTextLeft.AddText("Joined ", lightText); + infoTextLeft.AddText(new DrawableDate(user.JoinDate), boldItalic); } infoTextLeft.NewLine(); - infoTextLeft.AddText("Last seen "); - infoTextLeft.AddText(user.LastVisit.LocalDateTime.ToShortDateString(), boldItalic); + infoTextLeft.AddText("Last seen ", lightText); + infoTextLeft.AddText(new DrawableDate(user.LastVisit), boldItalic); infoTextLeft.NewParagraph(); if (user.PlayStyle?.Length > 0) { - infoTextLeft.AddText("Plays with "); + infoTextLeft.AddText("Plays with ", lightText); infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic); } @@ -411,23 +419,6 @@ namespace osu.Game.Overlays.Profile } } - // These could be local functions when C# 7 enabled - - private OsuSpriteText createScoreText(string text) => new OsuSpriteText - { - TextSize = 14, - Text = text - }; - - private OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText - { - TextSize = 14, - Font = @"Exo2.0-Bold", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Text = text - }; - private void tryAddInfoRightLine(FontAwesome icon, string str, string url = null) { if (string.IsNullOrEmpty(str)) return; @@ -436,10 +427,12 @@ namespace osu.Game.Overlays.Profile if (url != null) { infoTextRight.AddLink(" " + str, url); - } else + } + else { infoTextRight.AddText(" " + str); } + infoTextRight.NewLine(); } diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index bb1a409f2e..509356ae04 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -54,12 +54,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks RightFlowContainer.SetLayoutPosition(text, 1); LeftFlowContainer.Add(new BeatmapMetadataContainer(Score.Beatmap)); - LeftFlowContainer.Add(new OsuSpriteText - { - Text = Score.Date.LocalDateTime.ToShortDateString(), - TextSize = 11, - Colour = OsuColour.Gray(0xAA), - }); + LeftFlowContainer.Add(new DrawableDate(Score.Date)); foreach (Mod mod in Score.Mods) modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) }); diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 2dde8a3d54..e8be8d1e44 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; @@ -40,14 +39,12 @@ namespace osu.Game.Overlays.Profile.Sections.Recent RelativeSizeAxes = Axes.X, }); - RightFlowContainer.Add(new OsuSpriteText + RightFlowContainer.Add(new DrawableDate(activity.CreatedAt) { - Text = activity.CreatedAt.LocalDateTime.ToShortDateString(), + TextSize = 13, + Colour = OsuColour.Gray(0xAA), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Font = "Exo2.0-RegularItalic", - TextSize = 12, - Colour = OsuColour.Gray(0xAA), }); var formatted = createMessage(); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6f7c92ab5a..01074318cd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -287,6 +287,7 @@ + From 2cb197d0c452d27139eb3dd6e29d3193c40a6f62 Mon Sep 17 00:00:00 2001 From: TocoToucan Date: Thu, 8 Mar 2018 11:35:00 +0300 Subject: [PATCH 19/58] Replace ConfigureBackgroundUpdate with OnEntering --- osu.Game/Screens/Play/Player.cs | 2 -- osu.Game/Screens/Play/PlayerLoader.cs | 2 -- osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs | 4 +++- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7ec72a0e0e..9b341fbfe5 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -277,8 +277,6 @@ namespace osu.Game.Screens.Play if (!loadedSuccessfully) return; - ConfigureBackgroundUpdate(); - Content.Alpha = 0; Content .ScaleTo(0.7f) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 042b4fc744..784dcf7657 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -88,8 +88,6 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); - ConfigureBackgroundUpdate(); - Content.ScaleTo(0.7f); contentIn(); diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index d83f7e087d..9942bf4ef5 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; +using osu.Framework.Screens; using osu.Game.Configuration; using osu.Game.Screens.Backgrounds; using OpenTK; @@ -42,8 +43,9 @@ namespace osu.Game.Screens.Play UserAudioOffset = config.GetBindable(OsuSetting.AudioOffset); } - protected void ConfigureBackgroundUpdate() + protected override void OnEntering(Screen last) { + base.OnEntering(last); DimLevel.ValueChanged += _ => UpdateBackgroundElements(); BlurLevel.ValueChanged += _ => UpdateBackgroundElements(); ShowStoryboard.ValueChanged += _ => UpdateBackgroundElements(); From 6d91889ca641258a9706c932d16d2aa836a8ba80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Mar 2018 22:16:47 +0900 Subject: [PATCH 20/58] Move player-specific configuration bindables back to player --- osu.Game/Screens/Play/Player.cs | 16 ++++++++++++---- .../Screens/Play/ScreenWithBeatmapBackground.cs | 6 ------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9b341fbfe5..d24ed53518 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -16,6 +17,7 @@ using osu.Framework.Screens; using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Cursor; using osu.Game.Online.API; @@ -43,6 +45,9 @@ namespace osu.Game.Screens.Play public bool AllowLeadIn { get; set; } = true; public bool AllowResults { get; set; } = true; + private Bindable mouseWheelDisabled; + private Bindable userAudioOffset; + public int RestartCount; public CursorContainer Cursor => RulesetContainer.Cursor; @@ -75,11 +80,14 @@ namespace osu.Game.Screens.Play private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true; [BackgroundDependencyLoader] - private void load(AudioManager audio, APIAccess api) + private void load(AudioManager audio, APIAccess api, OsuConfigManager config) { this.api = api; sampleRestart = audio.Sample.Get(@"Gameplay/restart"); + mouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); + userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + WorkingBeatmap working = Beatmap.Value; Beatmap beatmap; @@ -131,8 +139,8 @@ namespace osu.Game.Screens.Play // the final usable gameplay clock with user-set offsets applied. var offsetClock = new FramedOffsetClock(adjustableClock); - UserAudioOffset.ValueChanged += v => offsetClock.Offset = v; - UserAudioOffset.TriggerChange(); + userAudioOffset.ValueChanged += v => offsetClock.Offset = v; + userAudioOffset.TriggerChange(); scoreProcessor = RulesetContainer.CreateScoreProcessor(); @@ -342,7 +350,7 @@ namespace osu.Game.Screens.Play Background?.FadeTo(1f, fade_out_duration); } - protected override bool OnWheel(InputState state) => MouseWheelDisabled.Value && !pauseContainer.IsPaused; + protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value && !pauseContainer.IsPaused; private void initializeStoryboard(bool asyncLoad) { diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index 9942bf4ef5..8e963a94a8 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -26,8 +26,6 @@ namespace osu.Game.Screens.Play protected Bindable DimLevel; protected Bindable BlurLevel; protected Bindable ShowStoryboard; - protected Bindable MouseWheelDisabled; - protected Bindable UserAudioOffset; #endregion @@ -37,10 +35,6 @@ namespace osu.Game.Screens.Play DimLevel = config.GetBindable(OsuSetting.DimLevel); BlurLevel = config.GetBindable(OsuSetting.BlurLevel); ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); - - MouseWheelDisabled = config.GetBindable(OsuSetting.MouseDisableWheel); - - UserAudioOffset = config.GetBindable(OsuSetting.AudioOffset); } protected override void OnEntering(Screen last) From 1f48cfb79af0a821832b5c92750e13470a71d4ec Mon Sep 17 00:00:00 2001 From: tgi74000 Date: Thu, 8 Mar 2018 17:35:20 +0100 Subject: [PATCH 21/58] Added Mirror Mod for Mania --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 1 + .../Mods/ManiaMirrorMod.cs | 28 +++++++++++++++++++ .../osu.Game.Rulesets.Mania.csproj | 1 + 3 files changed, 30 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 16b6888f2b..7c257bf719 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -91,6 +91,7 @@ namespace osu.Game.Rulesets.Mania }, new ManiaModRandom(), new ManiaModDualStages(), + new ManiaMirrorMod(), new MultiMod { Mods = new Mod[] diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs new file mode 100644 index 0000000000..cbcbd9f329 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; +using System.Linq; + +namespace osu.Game.Rulesets.Mania.Mods +{ + public class ManiaMirrorMod : Mod, IApplicableToRulesetContainer + { + public override string Name => "Mirror"; + public override string ShortenedName => "MR"; + public override ModType Type => ModType.Special; + public override double ScoreMultiplier => 1; + public override bool Ranked => true; + + public void ApplyToRulesetContainer(RulesetContainer rulesetContainer) + { + var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns; + + rulesetContainer.Objects.OfType().ForEach(h => h.Column = -(h.Column) + (availableColumns)-1); + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index a09b3e93a7..3c80e21ff2 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -81,6 +81,7 @@ + From 6ad962fc8b7ec6e7390be778012d17988cb81777 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Mar 2018 14:34:05 +0900 Subject: [PATCH 22/58] Interpolate ParallaxContainer's scale Things were a bit jumpy when a screen was adjusting `ParallaxAmount`. This smoothes the applied scale changes to look great again. Most noticeable when hitting the retry hotkey (`~`) from gameplay. --- osu.Game/Graphics/Containers/ParallaxContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index febe52d775..97d6225534 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -66,8 +66,10 @@ namespace osu.Game.Graphics.Containers { Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount; - content.Position = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), content.Position, offset, 0, 1000, Easing.OutQuint); - content.Scale = new Vector2(1 + ParallaxAmount); + 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); } firstUpdate = false; From 25fb527cc7bd7f1d1c3a855db9ca2281ee3175a3 Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 9 Mar 2018 15:51:00 +0530 Subject: [PATCH 23/58] Remove previous fix and move filtered logic to carousel. - Add an optional bool parameter to SelectBeatmap to skip selecting filtered maps --- osu.Game/Screens/Select/BeatmapCarousel.cs | 31 +++++++++++++-------- osu.Game/Screens/Select/SongSelect.cs | 32 ---------------------- 2 files changed, 20 insertions(+), 43 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 9793440348..02bad82ca9 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -169,20 +169,29 @@ namespace osu.Game.Screens.Select }); } - public void SelectBeatmap(BeatmapInfo beatmap) + /// + /// Selects a given beatmap on the carousel. + /// + /// The beatmap to select. + /// Whether to skip selecting filtered beatmaps. + /// True if a selection was made, false if it was skipped. + public bool SelectBeatmap(BeatmapInfo beatmap, bool skipFiltered = false) { if (beatmap?.Hidden != false) - return; + return false; - foreach (CarouselBeatmapSet group in beatmapSets) - { - var item = group.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); - if (item != null) - { - select(item); - return; - } - } + var group = beatmapSets.FirstOrDefault(s => s.BeatmapSet.OnlineBeatmapSetID == beatmap.BeatmapSet.OnlineBeatmapSetID); + + if (group == null || !skipFiltered && group.Filtered) + return false; + + var item = group.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + + if (item == null || !skipFiltered && item.Filtered) + return false; + + select(item); + return true; } /// diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d4fd64dcd9..2c8dcae3cf 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -267,10 +267,7 @@ namespace osu.Game.Screens.Select protected void WorkingBeatmapChanged(WorkingBeatmap beatmap) { if (IsCurrentScreen) - { Carousel.SelectBeatmap(beatmap?.BeatmapInfo); - ensurePlayableRuleset(); - } } /// @@ -328,7 +325,6 @@ namespace osu.Game.Screens.Select { base.OnEntering(last); - ensurePlayableRuleset(); Content.FadeInFromZero(250); FilterControl.Activate(); } @@ -456,34 +452,6 @@ namespace osu.Game.Screens.Select } } - private void ensurePlayableRuleset() - { - if (Beatmap.IsDefault) - // DummyBeatmap won't be playable anyway - return; - - bool conversionAllowed = rulesetConversionAllowed.Value; - int? currentRuleset = Ruleset.Value.ID; - int beatmapRuleset = Beatmap.Value.BeatmapInfo.RulesetID; - - if (currentRuleset == beatmapRuleset || conversionAllowed && beatmapRuleset == 0) - // Current beatmap is playable, nothing more to do - return; - - // Otherwise, first check if the current beatmapset has any playable beatmaps - BeatmapInfo beatmap = Beatmap.Value.BeatmapSetInfo.Beatmaps?.FirstOrDefault(b => b.RulesetID == currentRuleset || conversionAllowed && b.RulesetID == 0); - - // If it does then update the WorkingBeatmap - if (beatmap != null) - { - Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap); - return; - } - - // If it doesn't, then update the current ruleset so that the current beatmap is playable - Ruleset.Value = Beatmap.Value.BeatmapInfo.Ruleset; - } - private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s); private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID)); From d04f47718fa73622a6610897357dd3c9de8acdfb Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 9 Mar 2018 16:22:59 +0530 Subject: [PATCH 24/58] Make song select choose random when initial selection fails. - Revert TestCasePlaySongSelect to master --- .../Visual/TestCasePlaySongSelect.cs | 100 ++---------------- osu.Game/Screens/Select/BeatmapCarousel.cs | 32 ++++-- osu.Game/Screens/Select/SongSelect.cs | 25 ++--- 3 files changed, 37 insertions(+), 120 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 8532962389..cede0160bc 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -11,7 +11,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.MathUtils; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Rulesets; using osu.Game.Screens.Select; @@ -56,22 +55,10 @@ namespace osu.Game.Tests.Visual public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; public new BeatmapCarousel Carousel => base.Carousel; - - public void SetRuleset(RulesetInfo ruleset) => Ruleset.Value = ruleset; - - public int? RulesetID => Ruleset.Value.ID; - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - // Necessary while running tests because gc is moody and uncollected object interferes with OnEntering test - Beatmap.ValueChanged -= WorkingBeatmapChanged; - } } [BackgroundDependencyLoader] - private void load(OsuGameBase game, OsuConfigManager config) + private void load(OsuGameBase game) { TestSongSelect songSelect = null; @@ -90,7 +77,6 @@ namespace osu.Game.Tests.Visual { if (deleteMaps) { - // TODO: check why this alone doesn't allow import test to run twice in the same session, probably because the delete op is not saved? manager.Delete(manager.GetAllUsableBeatmapSets()); game.Beatmap.SetDefault(); } @@ -102,8 +88,6 @@ namespace osu.Game.Tests.Visual } Add(songSelect = new TestSongSelect()); - - songSelect?.SetRuleset(rulesets.AvailableRulesets.First()); }); loadNewSongSelect(true); @@ -118,36 +102,6 @@ namespace osu.Game.Tests.Visual { for (int i = 0; i < 100; i += 10) manager.Import(createTestBeatmapSet(i)); - - // also import a set which has a single non - osu ruleset beatmap - manager.Import(new BeatmapSetInfo - { - OnlineBeatmapSetID = 1993, - Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), - Metadata = new BeatmapMetadata - { - OnlineBeatmapSetID = 1993, - // 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), - AuthorString = "Some Guy " + RNG.Next(0, 9), - }, - Beatmaps = new List - { - new BeatmapInfo - { - OnlineBeatmapID = 1994, - Ruleset = rulesets.AvailableRulesets.ElementAt(3), - RulesetID = 3, - Path = "normal.fruits", - Version = "Normal", - BaseDifficulty = new BeatmapDifficulty - { - OverallDifficulty = 3.5f, - } - }, - } - }); }); AddWaitStep(3); @@ -161,45 +115,6 @@ namespace osu.Game.Tests.Visual AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; }); AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; }); AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; }); - - // Test that song select sets a playable beatmap while entering - AddStep(@"Remove song select", () => - { - Remove(songSelect); - songSelect.Dispose(); - songSelect = null; - }); - AddStep(@"Set non-osu beatmap", () => game.Beatmap.Value = manager.GetWorkingBeatmap(manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID != 0))); - AddAssert(@"Non-osu beatmap set", () => game.Beatmap.Value.BeatmapInfo.RulesetID != 0); - loadNewSongSelect(); - AddWaitStep(3); - AddAssert(@"osu beatmap set", () => game.Beatmap.Value.BeatmapInfo.RulesetID == 0); - - // Test that song select changes WorkingBeatmap to be playable in current ruleset when updated externally - AddStep(@"Try set non-osu beatmap", () => - { - var testMap = manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID != 0); - songSelect.SetRuleset(rulesets.AvailableRulesets.First()); - game.Beatmap.Value = manager.GetWorkingBeatmap(testMap); - }); - AddAssert(@"Beatmap changed to osu", () => songSelect.RulesetID == 0 && game.Beatmap.Value.BeatmapInfo.RulesetID == 0); - - // Test that song select updates WorkingBeatmap when ruleset conversion is disabled - AddStep(@"Disable beatmap conversion", () => config.Set(OsuSetting.ShowConvertedBeatmaps, false)); - AddStep(@"Set osu beatmap taiko rs", () => - { - game.Beatmap.Value = manager.GetWorkingBeatmap(manager.GetAllUsableBeatmapSets().First().Beatmaps.First(b => b.RulesetID == 0)); - songSelect.SetRuleset(rulesets.AvailableRulesets.First(r => r.ID == 1)); - }); - AddAssert(@"taiko beatmap set", () => songSelect.RulesetID == 1); - - // Test that song select changes the active ruleset when externally set beatmapset has no playable beatmaps - AddStep(@"Set fruits only beatmapset", () => - { - songSelect.SetRuleset(rulesets.AvailableRulesets.First()); - game.Beatmap.Value = manager.GetWorkingBeatmap(manager.QueryBeatmapSet(b => b.OnlineBeatmapSetID == 1993).Beatmaps.First()); - }); - AddAssert(@"Ruleset changed to fruits", () => songSelect.RulesetID == game.Beatmap.Value.BeatmapInfo.RulesetID); } private BeatmapSetInfo createTestBeatmapSet(int i) @@ -221,8 +136,7 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1234 + i, - Ruleset = rulesets.AvailableRulesets.ElementAt(0), - RulesetID = 0, + Ruleset = rulesets.AvailableRulesets.First(), Path = "normal.osu", Version = "Normal", BaseDifficulty = new BeatmapDifficulty @@ -233,9 +147,8 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1235 + i, - Ruleset = rulesets.AvailableRulesets.First(r => r.ID != 0), - RulesetID = 1, - Path = "hard.taiko", + Ruleset = rulesets.AvailableRulesets.First(), + Path = "hard.osu", Version = "Hard", BaseDifficulty = new BeatmapDifficulty { @@ -245,9 +158,8 @@ namespace osu.Game.Tests.Visual new BeatmapInfo { OnlineBeatmapID = 1236 + i, - Ruleset = rulesets.AvailableRulesets.ElementAt(2), - RulesetID = 2, - Path = "insane.fruits", + Ruleset = rulesets.AvailableRulesets.First(), + Path = "insane.osu", Version = "Insane", BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 02bad82ca9..287584bf2f 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -171,27 +171,41 @@ namespace osu.Game.Screens.Select /// /// Selects a given beatmap on the carousel. + /// + /// If skipFiltered is true, we will try to select another unfiltered beatmap in the same set. If the + /// entire set is filtered, no selection is made. /// /// The beatmap to select. /// Whether to skip selecting filtered beatmaps. - /// True if a selection was made, false if it was skipped. + /// True if a selection was made, False if it wasn't. public bool SelectBeatmap(BeatmapInfo beatmap, bool skipFiltered = false) { if (beatmap?.Hidden != false) return false; - var group = beatmapSets.FirstOrDefault(s => s.BeatmapSet.OnlineBeatmapSetID == beatmap.BeatmapSet.OnlineBeatmapSetID); + foreach (CarouselBeatmapSet set in beatmapSets) + { + if (skipFiltered && set.Filtered) + continue; - if (group == null || !skipFiltered && group.Filtered) - return false; + var item = set.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); - var item = group.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + if (item == null) + // The beatmap that needs to be selected doesn't exist in this set + continue; - if (item == null || !skipFiltered && item.Filtered) - return false; + if (skipFiltered && item.Filtered) + // The beatmap exists in this set but is filtered, so look for the first unfiltered map in the set + item = set.Beatmaps.FirstOrDefault(b => !b.Filtered); - select(item); - return true; + if (item != null) + { + select(item); + return true; + } + } + + return false; } /// diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 2c8dcae3cf..461b17338d 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Linq; using System.Threading; using OpenTK; using OpenTK.Input; @@ -10,14 +9,12 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; 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.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Overlays; @@ -66,8 +63,6 @@ namespace osu.Game.Screens.Select private SampleChannel sampleChangeDifficulty; private SampleChannel sampleChangeBeatmap; - private Bindable rulesetConversionAllowed; - private CancellationTokenSource initialAddSetsTask; private DependencyContainer dependencies; @@ -184,7 +179,7 @@ namespace osu.Game.Screens.Select } [BackgroundDependencyLoader(permitNulls: true)] - private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours, OsuConfigManager config) + private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours) { dependencies.CacheAs(this); @@ -199,8 +194,6 @@ namespace osu.Game.Screens.Select if (this.beatmaps == null) this.beatmaps = beatmaps; - rulesetConversionAllowed = config.GetBindable(OsuSetting.ShowConvertedBeatmaps); - if (osu != null) Ruleset.BindTo(osu.Ruleset); @@ -459,16 +452,14 @@ namespace osu.Game.Screens.Select private void carouselBeatmapsLoaded() { - if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false) + if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, true)) + return; + + if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom()) { - Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo); - } - else if (Carousel.SelectedBeatmapSet == null) - { - if (!Carousel.SelectNextRandom()) - // in the case random selection failed, we want to trigger selectionChanged - // to show the dummy beatmap (we have nothing else to display). - carouselSelectionChanged(null); + // in the case random selection failed, we want to trigger selectionChanged + // to show the dummy beatmap (we have nothing else to display). + carouselSelectionChanged(null); } } From 217dd2ecdc273af42124b89fa2c902828d545c95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Mar 2018 21:23:03 +0900 Subject: [PATCH 25/58] Initial push for better decoders --- .../Formats/LegacyBeatmapDecoderTest.cs | 16 +- .../Formats/LegacyStoryboardDecoderTest.cs | 4 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 4 +- .../Beatmaps/IO/OszArchiveReaderTest.cs | 2 +- osu.Game/Beatmaps/Beatmap.cs | 7 +- osu.Game/Beatmaps/BeatmapManager.cs | 6 +- .../Beatmaps/BeatmapManager_WorkingBeatmap.cs | 20 +- osu.Game/Beatmaps/Formats/Decoder.cs | 81 +++-- .../Beatmaps/Formats/JsonBeatmapDecoder.cs | 14 +- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 40 +-- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 59 +--- .../Formats/LegacyStoryboardDecoder.cs | 296 +++++++++--------- .../Objects/Legacy/ConvertHitObjectParser.cs | 4 +- .../Tests/Beatmaps/BeatmapConversionTest.cs | 4 +- osu.Game/Tests/Visual/TestCasePlayer.cs | 2 +- 15 files changed, 250 insertions(+), 309 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index ab10da2cd1..b74be134c1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var beatmap = decoder.DecodeBeatmap(stream); + var beatmap = decoder.Decode(stream); var beatmapInfo = beatmap.BeatmapInfo; var metadata = beatmap.Metadata; @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var beatmapInfo = decoder.DecodeBeatmap(stream).BeatmapInfo; + var beatmapInfo = decoder.Decode(stream).BeatmapInfo; int[] expectedBookmarks = { @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var beatmap = decoder.DecodeBeatmap(stream); + var beatmap = decoder.Decode(stream); var beatmapInfo = beatmap.BeatmapInfo; var metadata = beatmap.Metadata; @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var difficulty = decoder.DecodeBeatmap(stream).BeatmapInfo.BaseDifficulty; + var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var beatmap = decoder.DecodeBeatmap(stream); + var beatmap = decoder.Decode(stream); var metadata = beatmap.Metadata; var breakPoint = beatmap.Breaks[0]; @@ -132,7 +132,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var beatmap = decoder.DecodeBeatmap(stream); + var beatmap = decoder.Decode(stream); var controlPoints = beatmap.ControlPointInfo; Assert.AreEqual(4, controlPoints.TimingPoints.Count); @@ -167,7 +167,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var comboColors = decoder.DecodeBeatmap(stream).ComboColors; + var comboColors = decoder.Decode(stream).ComboColors; Color4[] expectedColors = { @@ -191,7 +191,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new StreamReader(resStream)) { - var hitObjects = decoder.DecodeBeatmap(stream).HitObjects; + var hitObjects = decoder.Decode(stream).HitObjects; var curveData = hitObjects[0] as IHasCurve; var positionData = hitObjects[0] as IHasPosition; diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index dce6c0f55b..1c0801c634 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -18,11 +18,11 @@ namespace osu.Game.Tests.Beatmaps.Formats [Test] public void TestDecodeStoryboardEvents() { - var decoder = new LegacyBeatmapDecoder(); + var decoder = new LegacyStoryboardDecoder(); using (var resStream = Resource.OpenResource("Himeringo - Yotsuya-san ni Yoroshiku (RLC) [Winber1's Extreme].osu")) using (var stream = new StreamReader(resStream)) { - var storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(stream); + var storyboard = decoder.Decode(stream); Assert.IsTrue(storyboard.HasDrawable); Assert.AreEqual(4, storyboard.Layers.Count()); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 89d96c774e..80dea9d01d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -159,7 +159,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var sr = new StreamReader(stream)) { - var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.DecodeBeatmap(sr); + var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr); using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms)) using (var sr2 = new StreamReader(ms)) @@ -168,7 +168,7 @@ namespace osu.Game.Tests.Beatmaps.Formats sw.Flush(); ms.Position = 0; - return (legacyDecoded, new JsonBeatmapDecoder().DecodeBeatmap(sr2)); + return (legacyDecoded, new JsonBeatmapDecoder().Decode(sr2)); } } } diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index 1f7246a119..29d25accbb 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps.IO BeatmapMetadata meta; using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; + meta = Decoder.GetDecoder(stream).Decode(stream).Metadata; Assert.AreEqual(241526, meta.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 4fd54e4364..9b00993b6e 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -22,6 +22,7 @@ namespace osu.Game.Beatmaps public BeatmapInfo BeatmapInfo = new BeatmapInfo(); public ControlPointInfo ControlPointInfo = new ControlPointInfo(); public List Breaks = new List(); + public List ComboColors = new List { new Color4(17, 136, 170, 255), @@ -85,9 +86,13 @@ namespace osu.Game.Beatmaps /// Constructs a new beatmap. /// /// The original beatmap to use the parameters of. - public Beatmap(Beatmap original = null) + public Beatmap(Beatmap original) : base(original) { } + + public Beatmap() + { + } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 1d6d8b6726..817a3388e2 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -301,7 +301,7 @@ namespace osu.Game.Beatmaps BeatmapMetadata metadata; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = Decoder.GetDecoder(stream).DecodeBeatmap(stream).Metadata; + metadata = Decoder.GetDecoder(stream).Decode(stream).Metadata; return new BeatmapSetInfo { @@ -328,8 +328,8 @@ namespace osu.Game.Beatmaps raw.CopyTo(ms); ms.Position = 0; - var decoder = Decoder.GetDecoder(sr); - Beatmap beatmap = decoder.DecodeBeatmap(sr); + var decoder = Decoder.GetDecoder(sr); + Beatmap beatmap = decoder.Decode(sr); beatmap.BeatmapInfo.Path = name; beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index a72c1adfcd..fb11684309 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Logging; using osu.Game.Beatmaps.Formats; using osu.Game.Graphics.Textures; using osu.Game.Storyboards; @@ -30,10 +31,7 @@ namespace osu.Game.Beatmaps try { using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) - { - Decoder decoder = Decoder.GetDecoder(stream); - return decoder.DecodeBeatmap(stream); - } + return Decoder.GetDecoder(stream).Decode(stream); } catch { @@ -78,23 +76,23 @@ namespace osu.Game.Beatmaps Storyboard storyboard; try { - using (var beatmap = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) + using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) { - Decoder decoder = Decoder.GetDecoder(beatmap); + var decoder = Decoder.GetDecoder(stream); // todo: support loading from both set-wide storyboard *and* beatmap specific. - if (BeatmapSetInfo?.StoryboardFile == null) - storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(beatmap); + storyboard = decoder.Decode(stream); else { - using (var reader = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) - storyboard = decoder.GetStoryboardDecoder().DecodeStoryboard(beatmap, reader); + using (var secondaryStream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile)))) + storyboard = decoder.Decode(stream, secondaryStream); } } } - catch + catch (Exception e) { + Logger.Error(e, "Storyboard failed to load"); storyboard = new Storyboard(); } diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index 1aae52208a..9f10485c5f 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -4,38 +4,64 @@ using System; using System.Collections.Generic; using System.IO; -using osu.Game.Storyboards; +using System.Linq; namespace osu.Game.Beatmaps.Formats { + public abstract class Decoder : Decoder + where TOutput : new() + { + protected virtual TOutput CreateTemplateObject() => new TOutput(); + + public TOutput Decode(StreamReader primaryStream, params StreamReader[] otherStreams) + { + var output = CreateTemplateObject(); + foreach (StreamReader stream in new[] { primaryStream }.Concat(otherStreams)) + ParseStreamInto(stream, output); + return output; + } + + protected abstract void ParseStreamInto(StreamReader stream, TOutput beatmap); + } + public abstract class Decoder { - private static readonly Dictionary> decoders = new Dictionary>(); + private static readonly Dictionary>> decoders = new Dictionary>>(); static Decoder() { - LegacyDecoder.Register(); + LegacyBeatmapDecoder.Register(); JsonBeatmapDecoder.Register(); + LegacyStoryboardDecoder.Register(); } /// /// Retrieves a to parse a . /// /// A stream pointing to the . - public static Decoder GetDecoder(StreamReader stream) + public static Decoder GetDecoder(StreamReader stream) + where T : new() { if (stream == null) throw new ArgumentNullException(nameof(stream)); + if (!decoders.TryGetValue(typeof(T), out var typedDecoders)) + throw new IOException(@"Unknown decoder type"); + string line; do - { line = stream.ReadLine()?.Trim(); } - while (line != null && line.Length == 0); + { + line = stream.ReadLine()?.Trim(); + } while (line != null && line.Length == 0); - if (line == null || !decoders.ContainsKey(line)) + if (line == null) throw new IOException(@"Unknown file format"); - return decoders[line](line); + var decoder = typedDecoders.Select(d => line.StartsWith(d.Key) ? d.Value : null).FirstOrDefault(); + if (decoder == null) + throw new IOException(@"Unknown file format"); + + return (Decoder)decoder.Invoke(line); } /// @@ -43,41 +69,12 @@ namespace osu.Game.Beatmaps.Formats /// /// A string in the file which triggers this decoder to be used. /// A function which constructs the given . - protected static void AddDecoder(string magic, Func constructor) + protected static void AddDecoder(string magic, Func constructor) { - decoders[magic] = constructor; + if (!decoders.TryGetValue(typeof(T), out var typedDecoders)) + decoders.Add(typeof(T), typedDecoders = new Dictionary>()); + + typedDecoders[magic] = constructor; } - - /// - /// Retrieves a to parse a - /// - public abstract Decoder GetStoryboardDecoder(); - - public virtual Beatmap DecodeBeatmap(StreamReader stream) - { - var beatmap = new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata(), - BaseDifficulty = new BeatmapDifficulty(), - }, - }; - - ParseBeatmap(stream, beatmap); - return beatmap; - } - - protected abstract void ParseBeatmap(StreamReader stream, Beatmap beatmap); - - public virtual Storyboard DecodeStoryboard(params StreamReader[] streams) - { - var storyboard = new Storyboard(); - foreach (StreamReader stream in streams) - ParseStoryboard(stream, storyboard); - return storyboard; - } - - protected abstract void ParseStoryboard(StreamReader stream, Storyboard storyboard); } } diff --git a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index b0798e5a87..add0f39280 100644 --- a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -3,20 +3,17 @@ using System.IO; using osu.Game.IO.Serialization; -using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public class JsonBeatmapDecoder : Decoder + public class JsonBeatmapDecoder : Decoder { public static void Register() { - AddDecoder("{", m => new JsonBeatmapDecoder()); + AddDecoder("{", m => new JsonBeatmapDecoder()); } - public override Decoder GetStoryboardDecoder() => this; - - protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) + protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap) { stream.BaseStream.Position = 0; stream.DiscardBufferedData(); @@ -26,10 +23,5 @@ namespace osu.Game.Beatmaps.Formats foreach (var hitObject in beatmap.HitObjects) hitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); } - - protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) - { - // throw new System.NotImplementedException(); - } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 7d4f8b5bf5..c54d81aa2b 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -4,6 +4,7 @@ using System; using System.Globalization; using System.IO; +using System.Linq; using OpenTK.Graphics; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects.Legacy; @@ -12,8 +13,10 @@ using osu.Framework; namespace osu.Game.Beatmaps.Formats { - public class LegacyBeatmapDecoder : LegacyDecoder + public class LegacyBeatmapDecoder : LegacyDecoder { + public const int LATEST_VERSION = 14; + private Beatmap beatmap; private bool hasCustomColours; @@ -22,6 +25,11 @@ namespace osu.Game.Beatmaps.Formats private LegacySampleBank defaultSampleBank; private int defaultSampleVolume = 100; + public static void Register() + { + AddDecoder(@"osu file format v", m => new LegacyBeatmapDecoder(int.Parse(m.Split('v').Last()))); + } + /// /// lazer's audio timings in general doesn't match stable. this is the result of user testing, albeit limited. /// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. @@ -35,29 +43,16 @@ namespace osu.Game.Beatmaps.Formats private readonly int offset = UniversalOffset; - public LegacyBeatmapDecoder() + public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version) { - } - - public LegacyBeatmapDecoder(string header) - { - BeatmapVersion = int.Parse(header.Substring(17)); - // BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off) - offset += BeatmapVersion < 5 ? 24 : 0; + offset += FormatVersion < 5 ? 24 : 0; } - protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) + protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap) { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - if (beatmap == null) - throw new ArgumentNullException(nameof(beatmap)); - this.beatmap = beatmap; - this.beatmap.BeatmapInfo.BeatmapVersion = BeatmapVersion; - - ParseContent(stream); + base.ParseStreamInto(stream, beatmap); // objects may be out of order *only* if a user has manually edited an .osu file. // unfortunately there are ranked maps in this state (example: https://osu.ppy.sh/s/594828). @@ -67,14 +62,9 @@ namespace osu.Game.Beatmaps.Formats hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); } - protected override bool ShouldSkipLine(string line) - { - if (base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_")) - return true; - return false; - } + protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_"); - protected override void ProcessSection(Section section, string line) + protected override void ParseLine(Beatmap beatmap, Section section, string line) { switch (section) { diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index e0fc439924..6a3fb82586 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -4,47 +4,20 @@ using System; using System.Collections.Generic; using System.IO; -using osu.Game.Beatmaps.Legacy; -using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public abstract class LegacyDecoder : Decoder + public abstract class LegacyDecoder : Decoder + where T : new() { - public static void Register() + protected readonly int FormatVersion; + + protected LegacyDecoder(int version) { - AddDecoder(@"osu file format v14", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v13", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v12", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v11", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v10", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v9", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v8", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v7", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v6", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v5", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v4", m => new LegacyBeatmapDecoder(m)); - AddDecoder(@"osu file format v3", m => new LegacyBeatmapDecoder(m)); - // TODO: differences between versions + FormatVersion = version; } - protected int BeatmapVersion; - - public override Decoder GetStoryboardDecoder() => new LegacyStoryboardDecoder(BeatmapVersion); - - public override Beatmap DecodeBeatmap(StreamReader stream) => new LegacyBeatmap(base.DecodeBeatmap(stream)); - - protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap) - { - throw new NotImplementedException(); - } - - protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) - { - throw new NotImplementedException(); - } - - protected void ParseContent(StreamReader stream) + protected override void ParseStreamInto(StreamReader stream, T beatmap) { Section section = Section.None; @@ -54,13 +27,6 @@ namespace osu.Game.Beatmaps.Formats if (ShouldSkipLine(line)) continue; - // It's already set in ParseBeatmap... why do it again? - //if (line.StartsWith(@"osu file format v")) - //{ - // Beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); - // continue; - //} - if (line.StartsWith(@"[") && line.EndsWith(@"]")) { if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) @@ -68,18 +34,13 @@ namespace osu.Game.Beatmaps.Formats continue; } - ProcessSection(section, line); + ParseLine(beatmap, section, line); } } - protected virtual bool ShouldSkipLine(string line) - { - if (string.IsNullOrWhiteSpace(line) || line.StartsWith("//")) - return true; - return false; - } + protected virtual bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.StartsWith("//"); - protected abstract void ProcessSection(Section section, string line); + protected abstract void ParseLine(T output, Section section, string line); protected KeyValuePair SplitKeyVal(string line, char separator) { diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index a4ff060c83..e35276ae1a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.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.Collections.Generic; using System.Globalization; using System.IO; using OpenTK; @@ -13,37 +13,34 @@ using osu.Game.Storyboards; namespace osu.Game.Beatmaps.Formats { - public class LegacyStoryboardDecoder : LegacyDecoder + public class LegacyStoryboardDecoder : LegacyDecoder { - private Storyboard storyboard; - private StoryboardSprite storyboardSprite; private CommandTimelineGroup timelineGroup; + private Storyboard storyboard; + private readonly Dictionary variables = new Dictionary(); public LegacyStoryboardDecoder() + : base(0) { } - public LegacyStoryboardDecoder(int beatmapVersion) + public static void Register() { - BeatmapVersion = beatmapVersion; + // note that this isn't completely correct + AddDecoder(@"osu file format v", m => new LegacyStoryboardDecoder()); + AddDecoder(@"[Events]", m => new LegacyStoryboardDecoder()); } - protected override void ParseStoryboard(StreamReader stream, Storyboard storyboard) + protected override void ParseStreamInto(StreamReader stream, Storyboard storyboard) { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - if (storyboard == null) - throw new ArgumentNullException(nameof(storyboard)); - this.storyboard = storyboard; - - ParseContent(stream); + base.ParseStreamInto(stream, storyboard); } - protected override void ProcessSection(Section section, string line) + protected override void ParseLine(Storyboard storyboard, Section section, string line) { switch (section) { @@ -80,38 +77,38 @@ namespace osu.Game.Beatmaps.Formats switch (type) { case EventType.Sprite: - { - var layer = parseLayer(split[1]); - var origin = parseOrigin(split[2]); - var path = cleanFilename(split[3]); - var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); - var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); - storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); - storyboard.GetLayer(layer).Add(storyboardSprite); - } + { + var layer = parseLayer(split[1]); + var origin = parseOrigin(split[2]); + var path = cleanFilename(split[3]); + var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); + var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); + storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); + storyboard.GetLayer(layer).Add(storyboardSprite); + } break; case EventType.Animation: - { - var layer = parseLayer(split[1]); - var origin = parseOrigin(split[2]); - var path = cleanFilename(split[3]); - var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); - var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); - var frameCount = int.Parse(split[6]); - var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); - var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; - storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); - storyboard.GetLayer(layer).Add(storyboardSprite); - } + { + var layer = parseLayer(split[1]); + var origin = parseOrigin(split[2]); + var path = cleanFilename(split[3]); + var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); + var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); + var frameCount = int.Parse(split[6]); + var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); + var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; + storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType); + storyboard.GetLayer(layer).Add(storyboardSprite); + } break; case EventType.Sample: - { - var time = double.Parse(split[1], CultureInfo.InvariantCulture); - var layer = parseLayer(split[2]); - var path = cleanFilename(split[3]); - var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; - storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); - } + { + var time = double.Parse(split[1], CultureInfo.InvariantCulture); + var layer = parseLayer(split[2]); + var path = cleanFilename(split[3]); + var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100; + storyboard.GetLayer(layer).Add(new StoryboardSample(path, time, volume)); + } break; } } @@ -124,120 +121,120 @@ namespace osu.Game.Beatmaps.Formats switch (commandType) { case "T": - { - var triggerName = split[1]; - var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue; - var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; - var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; - timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); - } + { + var triggerName = split[1]; + var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue; + var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; + var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; + timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); + } break; case "L": - { - var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); - var loopCount = int.Parse(split[2]); - timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); - } + { + var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); + var loopCount = int.Parse(split[2]); + timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); + } break; default: + { + if (string.IsNullOrEmpty(split[3])) + split[3] = split[2]; + + var easing = (Easing)int.Parse(split[1]); + var startTime = double.Parse(split[2], CultureInfo.InvariantCulture); + var endTime = double.Parse(split[3], CultureInfo.InvariantCulture); + + switch (commandType) { - if (string.IsNullOrEmpty(split[3])) - split[3] = split[2]; - - var easing = (Easing)int.Parse(split[1]); - var startTime = double.Parse(split[2], CultureInfo.InvariantCulture); - var endTime = double.Parse(split[3], CultureInfo.InvariantCulture); - - switch (commandType) + case "F": { - case "F": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); - } - break; - case "S": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue)); - } - break; - case "V": - { - var startX = float.Parse(split[4], CultureInfo.InvariantCulture); - var startY = float.Parse(split[5], CultureInfo.InvariantCulture); - var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; - var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; - timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); - } - break; - case "R": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue)); - } - break; - case "M": - { - var startX = float.Parse(split[4], CultureInfo.InvariantCulture); - var startY = float.Parse(split[5], CultureInfo.InvariantCulture); - var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; - var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; - timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); - timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); - } - break; - case "MX": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); - } - break; - case "MY": - { - var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); - var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; - timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); - } - break; - case "C": - { - var startRed = float.Parse(split[4], CultureInfo.InvariantCulture); - var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture); - var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture); - var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed; - var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen; - var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue; - timelineGroup?.Colour.Add(easing, startTime, endTime, - new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), - new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); - } - break; - case "P": - { - var type = split[4]; - switch (type) - { - case "A": - timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); - break; - case "H": - timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime); - break; - case "V": - timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); - break; - } - } - break; - default: - throw new InvalidDataException($@"Unknown command type: {commandType}"); + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); } + break; + case "S": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startValue), new Vector2(endValue)); + } + break; + case "V": + { + var startX = float.Parse(split[4], CultureInfo.InvariantCulture); + var startY = float.Parse(split[5], CultureInfo.InvariantCulture); + var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; + var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; + timelineGroup?.Scale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); + } + break; + case "R": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue)); + } + break; + case "M": + { + var startX = float.Parse(split[4], CultureInfo.InvariantCulture); + var startY = float.Parse(split[5], CultureInfo.InvariantCulture); + var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; + var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; + timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); + timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); + } + break; + case "MX": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); + } + break; + case "MY": + { + var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); + var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; + timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); + } + break; + case "C": + { + var startRed = float.Parse(split[4], CultureInfo.InvariantCulture); + var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture); + var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture); + var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed; + var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen; + var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue; + timelineGroup?.Colour.Add(easing, startTime, endTime, + new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), + new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); + } + break; + case "P": + { + var type = split[4]; + switch (type) + { + case "A": + timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); + break; + case "H": + timelineGroup?.FlipH.Add(easing, startTime, endTime, true, startTime == endTime); + break; + case "V": + timelineGroup?.FlipV.Add(easing, startTime, endTime, true, startTime == endTime); + break; + } + } + break; + default: + throw new InvalidDataException($@"Unknown command type: {commandType}"); } + } break; } } @@ -269,6 +266,7 @@ namespace osu.Game.Beatmaps.Formats case LegacyOrigins.BottomRight: return Anchor.BottomRight; } + throw new InvalidDataException($@"Unknown origin: {value}"); } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index ce292ef223..5084b28cf2 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -188,8 +188,8 @@ namespace osu.Game.Rulesets.Objects.Legacy string[] split = str.Split(':'); - var bank = (LegacyDecoder.LegacySampleBank)Convert.ToInt32(split[0]); - var addbank = (LegacyDecoder.LegacySampleBank)Convert.ToInt32(split[1]); + var bank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[0]); + var addbank = (LegacyBeatmapDecoder.LegacySampleBank)Convert.ToInt32(split[1]); // Let's not implement this for now, because this doesn't fit nicely into the bank structure //string sampleFile = split2.Length > 4 ? split2[4] : string.Empty; diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 219d805bc1..8505498e4f 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -112,9 +112,9 @@ namespace osu.Game.Tests.Beatmaps using (var resStream = openResource($"{resource_namespace}.{name}.osu")) using (var stream = new StreamReader(resStream)) { - var decoder = Decoder.GetDecoder(stream); + var decoder = Decoder.GetDecoder(stream); ((LegacyBeatmapDecoder)decoder).ApplyOffsets = false; - return decoder.DecodeBeatmap(stream); + return decoder.Decode(stream); } } diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index 181ed5e0e6..d835adb54f 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) using (var reader = new StreamReader(stream)) - beatmap = Game.Beatmaps.Formats.Decoder.GetDecoder(reader).DecodeBeatmap(reader); + beatmap = Game.Beatmaps.Formats.Decoder.GetDecoder(reader).Decode(reader); return beatmap; } From 2b0309b26d905a2c5a1448d6bdf4f74863374e15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Mar 2018 21:29:13 +0900 Subject: [PATCH 26/58] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 6372fb22c1..214035c3d4 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 6372fb22c1c85f600921a139849b8dedf71026d5 +Subproject commit 214035c3d4974a9507fef8670000cef8326f1f5e From 2c0488b1f17ac169632cc6e575318ddfd9d360e6 Mon Sep 17 00:00:00 2001 From: naoey Date: Fri, 9 Mar 2018 19:39:28 +0530 Subject: [PATCH 27/58] Invert bool, add test, and handle ruleset change. --- .../Visual/TestCaseBeatmapCarousel.cs | 42 ++++++++++++++++++- osu.Game/Screens/Select/BeatmapCarousel.cs | 10 ++--- osu.Game/Screens/Select/SongSelect.cs | 11 +++-- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index fe26366362..c68e548f44 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -12,6 +12,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Rulesets; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; @@ -22,6 +23,7 @@ namespace osu.Game.Tests.Visual public class TestCaseBeatmapCarousel : OsuTestCase { private TestBeatmapCarousel carousel; + private RulesetStore rulesets; public override IReadOnlyList RequiredTypes => new[] { @@ -46,8 +48,10 @@ namespace osu.Game.Tests.Visual private const int set_count = 5; [BackgroundDependencyLoader] - private void load() + private void load(RulesetStore rulesets) { + this.rulesets = rulesets; + Add(carousel = new TestBeatmapCarousel { RelativeSizeAxes = Axes.Both, @@ -75,6 +79,7 @@ namespace osu.Game.Tests.Visual testRemoveAll(); testEmptyTraversal(); testHiding(); + testSelectingFilteredRuleset(); } private void ensureRandomFetchSuccess() => @@ -363,6 +368,41 @@ namespace osu.Game.Tests.Visual } } + private void testSelectingFilteredRuleset() + { + var testMixed = createTestBeatmapSet(set_count + 1); + AddStep("add mixed ruleset beatmapset", () => + { + for (int i = 0; i <= 2; i++) + { + testMixed.Beatmaps[i].Ruleset = rulesets.AvailableRulesets.ElementAt(i); + testMixed.Beatmaps[i].RulesetID = i; + } + + carousel.UpdateBeatmapSet(testMixed); + }); + AddStep("filter to ruleset 0", () => + carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false)); + AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); + AddAssert("unfiltered beatmap selected", () => carousel.SelectedBeatmap.Equals(testMixed.Beatmaps[0])); + + AddStep("remove mixed set", () => + { + carousel.RemoveBeatmapSet(testMixed); + testMixed = null; + }); + var testSingle = createTestBeatmapSet(set_count + 2); + testSingle.Beatmaps.ForEach(b => + { + b.Ruleset = rulesets.AvailableRulesets.ElementAt(1); + b.RulesetID = b.Ruleset.ID ?? 1; + }); + AddStep("add single ruleset beatmapset", () => carousel.UpdateBeatmapSet(testSingle)); + AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testSingle.Beatmaps[0], false)); + checkNoSelection(); + AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); + } + private BeatmapSetInfo createTestBeatmapSet(int id) { return new BeatmapSetInfo diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 287584bf2f..c2bb155753 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -172,20 +172,20 @@ namespace osu.Game.Screens.Select /// /// Selects a given beatmap on the carousel. /// - /// If skipFiltered is true, we will try to select another unfiltered beatmap in the same set. If the + /// If bypassFilters is false, we will try to select another unfiltered beatmap in the same set. If the /// entire set is filtered, no selection is made. /// /// The beatmap to select. - /// Whether to skip selecting filtered beatmaps. + /// Whether to select the beatmap even if it is filtered (i.e., not visible on carousel). /// True if a selection was made, False if it wasn't. - public bool SelectBeatmap(BeatmapInfo beatmap, bool skipFiltered = false) + public bool SelectBeatmap(BeatmapInfo beatmap, bool bypassFilters = true) { if (beatmap?.Hidden != false) return false; foreach (CarouselBeatmapSet set in beatmapSets) { - if (skipFiltered && set.Filtered) + if (!bypassFilters && set.Filtered) continue; var item = set.Beatmaps.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); @@ -194,7 +194,7 @@ namespace osu.Game.Screens.Select // The beatmap that needs to be selected doesn't exist in this set continue; - if (skipFiltered && item.Filtered) + if (!bypassFilters && item.Filtered) // The beatmap exists in this set but is filtered, so look for the first unfiltered map in the set item = set.Beatmaps.FirstOrDefault(b => !b.Filtered); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 461b17338d..b12ab69edd 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -259,8 +259,13 @@ namespace osu.Game.Screens.Select protected void WorkingBeatmapChanged(WorkingBeatmap beatmap) { - if (IsCurrentScreen) - Carousel.SelectBeatmap(beatmap?.BeatmapInfo); + if (IsCurrentScreen && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false)) + // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch + if (beatmap?.BeatmapInfo?.Ruleset != null && beatmap.BeatmapInfo.Ruleset != Ruleset.Value) + { + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + Carousel.SelectBeatmap(beatmap.BeatmapInfo); + } } /// @@ -452,7 +457,7 @@ namespace osu.Game.Screens.Select private void carouselBeatmapsLoaded() { - if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, true)) + if (!Beatmap.IsDefault && Beatmap.Value.BeatmapSetInfo?.DeletePending == false && Beatmap.Value.BeatmapSetInfo?.Protected == false && Carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false)) return; if (Carousel.SelectedBeatmapSet == null && !Carousel.SelectNextRandom()) From 7cabc54f646094964bc8220e6d7cd094cf37cfaf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 10 Mar 2018 00:48:48 +0900 Subject: [PATCH 28/58] Fix major regression (framework revert) --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 214035c3d4..6915954abd 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 214035c3d4974a9507fef8670000cef8326f1f5e +Subproject commit 6915954abdba64e72f698aa58698b00159f3678d From 8ed5fce43a46b3c0f97fb939e6c24c371b2740dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Sat, 10 Mar 2018 01:11:56 +0900 Subject: [PATCH 29/58] Split out the slider head into a separate drawable hitobject --- .../Objects/Drawables/DrawableSlider.cs | 9 ++---- .../Objects/Drawables/DrawableSliderHead.cs | 32 +++++++++++++++++++ .../Objects/Drawables/DrawableSliderTail.cs | 4 ++- .../osu.Game.Rulesets.Osu.csproj | 1 + 4 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index f715ed075c..5b9ed4d259 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Judgements; using osu.Framework.Graphics.Primitives; using osu.Game.Configuration; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Objects.Drawables @@ -55,8 +54,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AlwaysPresent = true, Alpha = 0 }, - HeadCircle = new DrawableHitCircle(s.HeadCircle) { Position = s.TailCircle.Position - s.Position }, - TailCircle = new DrawableSliderTail(s.TailCircle) { Position = s.TailCircle.Position - s.Position } + HeadCircle = new DrawableSliderHead(s, s.HeadCircle), + TailCircle = new DrawableSliderTail(s, s.TailCircle) }; components.Add(Body); @@ -103,10 +102,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); - //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice. - if (!HeadCircle.IsHit) - HeadCircle.Position = slider.CurvePositionAt(completionProgress); - foreach (var c in components.OfType()) c.UpdateProgress(completionProgress); foreach (var c in components.OfType()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0)); foreach (var t in components.OfType()) t.Tracking = Ball.Tracking; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs new file mode 100644 index 0000000000..cf36d5fc14 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Objects.Types; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Objects.Drawables +{ + public class DrawableSliderHead : DrawableHitCircle + { + private readonly Slider slider; + + public DrawableSliderHead(Slider slider, HitCircle h) + : base(h) + { + this.slider = slider; + + Position = HitObject.Position - slider.Position; + } + + protected override void Update() + { + base.Update(); + + double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); + + //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice. + if (!IsHit) + Position = slider.CurvePositionAt(completionProgress); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index b907aea8c3..b277e7df7a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public bool Tracking { get; set; } - public DrawableSliderTail(HitCircle hitCircle) + public DrawableSliderTail(Slider slider, HitCircle hitCircle) : base(hitCircle) { Origin = Anchor.Centre; @@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables FillMode = FillMode.Fit; AlwaysPresent = true; + + Position = HitObject.Position - slider.Position; } protected override void CheckForJudgements(bool userTriggered, double timeOffset) diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 8e8a01b009..92cac71ad3 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -87,6 +87,7 @@ + From ed20e31bbe1e95ee642d6357fb08e278ede68bad Mon Sep 17 00:00:00 2001 From: tgi74000 Date: Sat, 10 Mar 2018 08:39:11 +0100 Subject: [PATCH 30/58] Removed redundant parentheses --- osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs index cbcbd9f329..e7f0e27733 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Mods { var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns; - rulesetContainer.Objects.OfType().ForEach(h => h.Column = -(h.Column) + (availableColumns)-1); + rulesetContainer.Objects.OfType().ForEach(h => h.Column = -h.Column + availableColumns - 1); } } } From a4dfeff2d775e018407c45eded431b33a9ec1a62 Mon Sep 17 00:00:00 2001 From: tgi74000 Date: Sat, 10 Mar 2018 08:44:46 +0100 Subject: [PATCH 31/58] Renamed ManiaMirrorMod to ManiaModMirror --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Mods/{ManiaMirrorMod.cs => ManiaModMirror.cs} | 2 +- osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game.Rulesets.Mania/Mods/{ManiaMirrorMod.cs => ManiaModMirror.cs} (91%) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 7c257bf719..268bc23640 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Mania }, new ManiaModRandom(), new ManiaModDualStages(), - new ManiaMirrorMod(), + new ManiaModMirror(), new MultiMod { Mods = new Mod[] diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs similarity index 91% rename from osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs rename to osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs index e7f0e27733..be3a0e02db 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMirrorMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs @@ -10,7 +10,7 @@ using System.Linq; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaMirrorMod : Mod, IApplicableToRulesetContainer + public class ManiaModMirror : Mod, IApplicableToRulesetContainer { public override string Name => "Mirror"; public override string ShortenedName => "MR"; diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 3c80e21ff2..52d8f66717 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -81,7 +81,7 @@ - + From 709fcf955239e89aa178614bfd72766dce32c76a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 10 Mar 2018 20:01:36 +0900 Subject: [PATCH 32/58] Update ISSUE_TEMPLATE --- ISSUE_TEMPLATE.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index ff930b07a3..2bff304fba 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,9 +1,11 @@ -osu!lazer is currently in early stages of development and is not yet ready for end users. Please avoid creating issues or bugs if you do not personally intend to fix them. Some acceptable topics include: +osu!lazer is currently still under heavy development! +Please ensure that you are making an issue for one of the following: + +- A bug with currently implemented features (not features that don't exist) +- A feature you are considering adding, so we can collaborate on feedback and design. - Discussions about technical design decisions -- Bugs that you have found and are personally willing and able to fix -- TODO lists of smaller tasks around larger features - -Basically, issues are not a place for you to get help. They are a place for developers to collaborate on the game. If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide. + +Screenshots and log files are highly welcomed. \ No newline at end of file From 9233266fe1311be39a71b826b652515f5398c743 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Mar 2018 00:44:00 +0900 Subject: [PATCH 33/58] Fix login failure for users with no country rank Closes #2148. --- osu.Game.Tests/Visual/TestCaseUserProfile.cs | 6 ++++++ osu.Game/Overlays/Profile/RankGraph.cs | 4 ++-- osu.Game/Overlays/UserProfileOverlay.cs | 15 +++++++++------ osu.Game/Users/UserStatistics.cs | 4 ++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/TestCaseUserProfile.cs b/osu.Game.Tests/Visual/TestCaseUserProfile.cs index 3caef777e7..1fc6c6f224 100644 --- a/osu.Game.Tests/Visual/TestCaseUserProfile.cs +++ b/osu.Game.Tests/Visual/TestCaseUserProfile.cs @@ -58,6 +58,12 @@ namespace osu.Game.Tests.Visual checkSupporterTag(false); + AddStep("Show null dummy", () => profile.ShowUser(new User + { + Username = @"Null", + Id = 1, + }, false)); + AddStep("Show ppy", () => profile.ShowUser(new User { Username = @"peppy", diff --git a/osu.Game/Overlays/Profile/RankGraph.cs b/osu.Game/Overlays/Profile/RankGraph.cs index 429049c7bc..369bdee65f 100644 --- a/osu.Game/Overlays/Profile/RankGraph.cs +++ b/osu.Game/Overlays/Profile/RankGraph.cs @@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Profile { placeholder.FadeIn(fade_duration, Easing.Out); - if (user == null) + if (user?.Statistics?.Ranks.Global == null) { rankText.Text = string.Empty; performanceText.Text = string.Empty; @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Profile return; } - int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Ranks.Global }; + int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Ranks.Global.Value }; ranks = userRanks.Select((x, index) => new KeyValuePair(index, x)).Where(x => x.Value != 0).ToArray(); if (ranks.Length > 1) diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index f3fd7aeac5..aed0a6d7c6 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -169,15 +169,18 @@ namespace osu.Game.Overlays { Header.User = user; - foreach (string id in user.ProfileOrder) + if (user.ProfileOrder != null) { - var sec = sections.FirstOrDefault(s => s.Identifier == id); - if (sec != null) + foreach (string id in user.ProfileOrder) { - sec.User.Value = user; + var sec = sections.FirstOrDefault(s => s.Identifier == id); + if (sec != null) + { + sec.User.Value = user; - sectionsContainer.Add(sec); - tabs.AddItem(sec); + sectionsContainer.Add(sec); + tabs.AddItem(sec); + } } } } diff --git a/osu.Game/Users/UserStatistics.cs b/osu.Game/Users/UserStatistics.cs index c29bc91d17..2504c9c62c 100644 --- a/osu.Game/Users/UserStatistics.cs +++ b/osu.Game/Users/UserStatistics.cs @@ -73,10 +73,10 @@ namespace osu.Game.Users public struct UserRanks { [JsonProperty(@"global")] - public int Global; + public int? Global; [JsonProperty(@"country")] - public int Country; + public int? Country; } } From db2a663234aea7180f577a807fb879c00f4d4908 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Mar 2018 01:26:03 +0900 Subject: [PATCH 34/58] Use private instead of protected --- osu.Game/Screens/Select/SongSelect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b12ab69edd..ca8a1cae41 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -214,7 +214,7 @@ namespace osu.Game.Screens.Select Beatmap.DisabledChanged += disabled => Carousel.AllowSelection = !disabled; Beatmap.TriggerChange(); - Beatmap.ValueChanged += WorkingBeatmapChanged; + Beatmap.ValueChanged += workingBeatmapChanged; } public void Edit(BeatmapInfo beatmap) @@ -257,7 +257,7 @@ namespace osu.Game.Screens.Select // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. private BeatmapInfo beatmapNoDebounce; - protected void WorkingBeatmapChanged(WorkingBeatmap beatmap) + private void workingBeatmapChanged(WorkingBeatmap beatmap) { if (IsCurrentScreen && !Carousel.SelectBeatmap(beatmap?.BeatmapInfo, false)) // If selecting new beatmap without bypassing filters failed, there's possibly a ruleset mismatch From a321bcf3af990a07a97369f7ee1158f06c329a8f Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sun, 11 Mar 2018 20:19:03 +0100 Subject: [PATCH 35/58] Fix check against LegacyID for non-default rulesets --- osu.Game/Rulesets/RulesetStore.cs | 2 +- osu.Game/Tests/Visual/TestCasePerformancePoints.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 92fbf25f04..4891b46c9d 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets context.SaveChanges(); //add any other modes - foreach (var r in instances.Where(r => r.LegacyID < 0)) + foreach (var r in instances.Where(r => r.LegacyID == null || r.LegacyID < 0)) if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) context.RulesetInfo.Add(r.RulesetInfo); diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index 5b32433467..c35c0308f9 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual private void load(BeatmapManager beatmaps) { var sets = beatmaps.GetAllUsableBeatmapSets(); - var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); + var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); } From 9c75c392f2edb4452f48a2e7ab9bb4e2b40de47e Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sun, 11 Mar 2018 21:27:49 +0100 Subject: [PATCH 36/58] Only check by null instead of sign --- osu.Game/Rulesets/RulesetStore.cs | 4 ++-- osu.Game/Tests/Visual/TestCasePerformancePoints.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 4891b46c9d..e621c3cf2b 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order - foreach (var r in instances.Where(r => r.LegacyID >= 0).OrderBy(r => r.LegacyID)) + foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) { if (context.RulesetInfo.SingleOrDefault(rsi => rsi.ID == r.RulesetInfo.ID) == null) context.RulesetInfo.Add(r.RulesetInfo); @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets context.SaveChanges(); //add any other modes - foreach (var r in instances.Where(r => r.LegacyID == null || r.LegacyID < 0)) + foreach (var r in instances.Where(r => r.LegacyID == null)) if (context.RulesetInfo.FirstOrDefault(ri => ri.InstantiationInfo == r.RulesetInfo.InstantiationInfo) == null) context.RulesetInfo.Add(r.RulesetInfo); diff --git a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs index c35c0308f9..7ca69c14b8 100644 --- a/osu.Game/Tests/Visual/TestCasePerformancePoints.cs +++ b/osu.Game/Tests/Visual/TestCasePerformancePoints.cs @@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual private void load(BeatmapManager beatmaps) { var sets = beatmaps.GetAllUsableBeatmapSets(); - var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || ruleset.LegacyID < 0 || b.RulesetID == ruleset.LegacyID); + var allBeatmaps = sets.SelectMany(s => s.Beatmaps).Where(b => ruleset.LegacyID == null || b.RulesetID == ruleset.LegacyID); allBeatmaps.ForEach(b => beatmapDisplays.Add(new BeatmapDisplay(b))); } From 33c721bcbb51d50f9d60d656208eb31538f7b6b2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 09:51:32 +0900 Subject: [PATCH 37/58] Fix post-merge errors --- osu-framework | 2 +- osu.Game/Screens/Play/Player.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu-framework b/osu-framework index 865b0df18b..59004b46f2 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 865b0df18bb240190cdf7a7f60d44c0b28c84c5f +Subproject commit 59004b46f2c96ac02fec712e66f9f96fe252f2fa diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 6453a72fc3..c8ff261a93 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -25,7 +25,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Ranking; using osu.Game.Storyboards.Drawables; From 209d91fe2131a8a9c8fd62f5be117bd6b2a69331 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 10:35:37 +0900 Subject: [PATCH 38/58] Fix duplicate item in csproj --- osu.Game/osu.Game.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 562f0ff788..4943db6852 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -379,7 +379,6 @@ - From 86d93ffe3c59a3b1fa57d4a8855298ac3ecc39b9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 10:49:50 +0900 Subject: [PATCH 39/58] Fix tooltip not working due to not handling input --- osu.Game/Graphics/DrawableDate.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 452443f9d0..a912f989e0 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -58,6 +58,8 @@ namespace osu.Game.Graphics Scheduler.AddDelayed(updateTimeWithReschedule, timeUntilNextUpdate); } + public override bool HandleMouseInput => true; + private void updateTime() => Text = date.Humanize(); public string TooltipText => date.ToString(); } From 1447ca55a3a128a3adb0fee0206178893640e256 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Mar 2018 11:02:02 +0900 Subject: [PATCH 40/58] Add xmldoc, make restrictSize private --- osu.Game/Skinning/SkinnableDrawable.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index a5f22f60a2..81abc9e80c 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -22,16 +22,20 @@ namespace osu.Game.Skinning private readonly string componentName; - /// - /// Whether a user-skin drawable should be limited to the size of our parent. - /// - public readonly bool RestrictSize; + private readonly bool restrictSize; + /// + /// + /// + /// The namespace-complete resource name for this skinnable element. + /// A function to create the default skin implementation of this element. + /// Whther to fallback to the default implementation when a custom skin is specified but not implementation is present. + /// Whether a user-skin drawable should be limited to the size of our parent. public SkinnableDrawable(string name, Func defaultImplementation, bool fallback = true, bool restrictSize = true) : base(fallback) { componentName = name; createDefault = defaultImplementation; - RestrictSize = restrictSize; + this.restrictSize = restrictSize; RelativeSizeAxes = Axes.Both; } @@ -41,7 +45,7 @@ namespace osu.Game.Skinning var drawable = skin.GetDrawableComponent(componentName); if (drawable != null) { - if (RestrictSize) + if (restrictSize) { drawable.RelativeSizeAxes = Axes.Both; drawable.Size = Vector2.One; From c70be29edacbdebb10dd874d15cd6dda145ef5ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Mar 2018 11:30:13 +0900 Subject: [PATCH 41/58] Move legacy conversion to LegacySkin --- .../Rulesets/Judgements/DrawableJudgement.cs | 19 +------------------ osu.Game/Skinning/LegacySkin.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 4664517312..8639812aff 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -40,24 +40,7 @@ namespace osu.Game.Rulesets.Judgements [BackgroundDependencyLoader] private void load(OsuColour colours) { - string legacyName = string.Empty; - switch (Judgement.Result) - { - case HitResult.Miss: - legacyName = "hit0"; - break; - case HitResult.Meh: - legacyName = "hit50"; - break; - case HitResult.Good: - legacyName = "hit100"; - break; - case HitResult.Great: - legacyName = "hit300"; - break; - } - - Child = new SkinnableDrawable($"Play/osu/{legacyName}", _ => JudgementText = new OsuSpriteText + Child = new SkinnableDrawable($"Play/{Judgement.Result}", _ => JudgementText = new OsuSpriteText { Text = Judgement.Result.GetDescription().ToUpper(), Font = @"Venera", diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index f03d1ce632..2caeed8480 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -29,6 +29,22 @@ namespace osu.Game.Skinning public override Drawable GetDrawableComponent(string componentName) { + switch (componentName) + { + case "Play/Miss": + componentName = "hit0"; + break; + case "Play/Meh": + componentName = "hit50"; + break; + case "Play/Good": + componentName = "hit100"; + break; + case "Play/Great": + componentName = "hit300"; + break; + } + var texture = textures.Get(componentName); if (texture == null) return null; From 1bcda4930ebc6736a239b4e6e4710525b03d3d4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Mar 2018 11:33:12 +0900 Subject: [PATCH 42/58] Add back beatmap version set --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index c54d81aa2b..915ea9b587 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -52,6 +52,8 @@ namespace osu.Game.Beatmaps.Formats protected override void ParseStreamInto(StreamReader stream, Beatmap beatmap) { this.beatmap = beatmap; + this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion; + base.ParseStreamInto(stream, beatmap); // objects may be out of order *only* if a user has manually edited an .osu file. From 46caab6310d74a0b3d7ba36a3edea53aca6b17b0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 11:56:49 +0900 Subject: [PATCH 43/58] Reorder arithmetic operation --- osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs index be3a0e02db..cfa5ef88b8 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Mods { var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns; - rulesetContainer.Objects.OfType().ForEach(h => h.Column = -h.Column + availableColumns - 1); + rulesetContainer.Objects.OfType().ForEach(h => h.Column = availableColumns - 1 - h.Column); } } } From fbb80edde1888523ff730d31d186a5d1466e3849 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 13:01:29 +0900 Subject: [PATCH 44/58] Minor cleanups --- osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs index 02560c8141..f4e3d54a3d 100644 --- a/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/ManiaDifficultyCalculator.cs @@ -32,11 +32,13 @@ namespace osu.Game.Rulesets.Mania private readonly List difficultyHitObjects = new List(); public ManiaDifficultyCalculator(Beatmap beatmap) - : base(beatmap) { + : base(beatmap) + { } public ManiaDifficultyCalculator(Beatmap beatmap, Mod[] mods) - : base(beatmap, mods) { + : base(beatmap, mods) + { } public override double Calculate(Dictionary categoryDifficulty = null) @@ -58,7 +60,6 @@ namespace osu.Game.Rulesets.Mania double starRating = calculateDifficulty() * star_scaling_factor; categoryDifficulty?.Add("Strain", starRating); - // categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate); return starRating; } From 81186f8423198b76a97a2d9846281d4a612cbe56 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 13:06:42 +0900 Subject: [PATCH 45/58] Apply beatmap converter mods in DifficultyCalculator --- osu.Game/Beatmaps/DifficultyCalculator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 798268d05f..d61c62a30b 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -24,9 +24,15 @@ namespace osu.Game.Beatmaps protected DifficultyCalculator(Beatmap beatmap, Mod[] mods = null) { - Beatmap = CreateBeatmapConverter(beatmap).Convert(beatmap); Mods = mods ?? new Mod[0]; + var converter = CreateBeatmapConverter(beatmap); + + foreach (var mod in Mods.OfType>()) + mod.ApplyToBeatmapConverter(converter); + + Beatmap = converter.Convert(beatmap); + ApplyMods(Mods); PreprocessHitObjects(); From 3cd203699b485067d79eed122e27fd822895e695 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 13:09:19 +0900 Subject: [PATCH 46/58] Apply beatmap converter mods in PerformanceCalculator --- osu.Game/Rulesets/Scoring/PerformanceCalculator.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs index ba16d78b37..c047a421fd 100644 --- a/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs +++ b/osu.Game/Rulesets/Scoring/PerformanceCalculator.cs @@ -2,7 +2,9 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Scoring @@ -23,9 +25,15 @@ namespace osu.Game.Rulesets.Scoring protected PerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score) { - Beatmap = CreateBeatmapConverter().Convert(beatmap); Score = score; + var converter = CreateBeatmapConverter(); + + foreach (var mod in score.Mods.OfType>()) + mod.ApplyToBeatmapConverter(converter); + + Beatmap = converter.Convert(beatmap); + var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods); diffCalc.Calculate(attributes); } From 2d9fcdcbd02c3f92c608d5f63ab0a7ab8705ff94 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 17:18:50 +0900 Subject: [PATCH 47/58] Fix slider circle overlays moving with the endpoints --- .../Edit/Layers/Selection/Overlays/SliderCircleOverlay.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleOverlay.cs b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleOverlay.cs index 3c7f8a067b..50a325d6cc 100644 --- a/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleOverlay.cs +++ b/osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderCircleOverlay.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Rulesets.Edit.Layers.Selection; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; @@ -14,12 +15,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Layers.Selection.Overlays public class SliderCircleOverlay : HitObjectOverlay { public SliderCircleOverlay(DrawableHitCircle sliderHead, DrawableSlider slider) - : this(sliderHead, sliderHead.Position, slider) + : this(sliderHead, Vector2.Zero, slider) { } public SliderCircleOverlay(DrawableSliderTail sliderTail, DrawableSlider slider) - : this(sliderTail, sliderTail.Position, slider) + : this(sliderTail, ((Slider)slider.HitObject).Curve.PositionAt(1), slider) { } From 7406cb290f655bb4953549fb6510eb13241df94e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 19:41:09 +0900 Subject: [PATCH 48/58] Split out test beatmap from TestCasePlayer into instantiable class --- .../Tests/TestCaseBananaShower.cs | 8 +- .../Tests/TestCaseCatchStacker.cs | 9 +- .../Tests/TestCaseHyperdash.cs | 5 +- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 725 ++++++++++++++++++ osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 7 +- osu.Game/Tests/Visual/TestCasePlayer.cs | 711 +---------------- osu.Game/osu.Game.csproj | 1 + 7 files changed, 744 insertions(+), 722 deletions(-) create mode 100644 osu.Game/Tests/Beatmaps/TestBeatmap.cs diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs index ecae154075..ec9dd15673 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseBananaShower.cs @@ -28,16 +28,14 @@ namespace osu.Game.Rulesets.Catch.Tests { } - protected override Beatmap CreateBeatmap() + protected override Beatmap CreateBeatmap(Ruleset ruleset) { var beatmap = new Beatmap { BeatmapInfo = new BeatmapInfo { - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 6, - } + BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 }, + Ruleset = ruleset.RulesetInfo } }; diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs index 518845208c..8e5843f40a 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseCatchStacker.cs @@ -15,19 +15,18 @@ namespace osu.Game.Rulesets.Catch.Tests { } - protected override Beatmap CreateBeatmap() + protected override Beatmap CreateBeatmap(Ruleset ruleset) { var beatmap = new Beatmap { BeatmapInfo = new BeatmapInfo { - BaseDifficulty = new BeatmapDifficulty - { - CircleSize = 6, - } + BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 }, + Ruleset = ruleset.RulesetInfo } }; + for (int i = 0; i < 512; i++) beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 }); diff --git a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs index c01791a923..7564adea8c 100644 --- a/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs +++ b/osu.Game.Rulesets.Catch/Tests/TestCaseHyperdash.cs @@ -15,9 +15,10 @@ namespace osu.Game.Rulesets.Catch.Tests { } - protected override Beatmap CreateBeatmap() + protected override Beatmap CreateBeatmap(Ruleset ruleset) { - var beatmap = new Beatmap(); + var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } }; + for (int i = 0; i < 512; i++) if (i % 5 < 3) diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs new file mode 100644 index 0000000000..a29ee03975 --- /dev/null +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -0,0 +1,725 @@ +// 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.Text; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using Decoder = osu.Game.Beatmaps.Formats.Decoder; + +namespace osu.Game.Tests.Beatmaps +{ + public class TestBeatmap : Beatmap + { + public TestBeatmap(RulesetInfo ruleset) + : base(createTestBeatmap()) + { + BeatmapInfo.Ruleset = ruleset; + } + + private static Beatmap testBeatmapCache; + private static Beatmap createTestBeatmap() + { + if (testBeatmapCache != null) + return testBeatmapCache; + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) + using (var reader = new StreamReader(stream)) + return testBeatmapCache = Decoder.GetDecoder(reader).DecodeBeatmap(reader); + } + + private const string test_beatmap_data = +@"osu file format v14 + +[General] +AudioLeadIn: 500 +PreviewTime: 53498 +Countdown: 0 +SampleSet: Soft +StackLeniency: 0.7 +Mode: 0 +LetterboxInBreaks: 0 +WidescreenStoryboard: 1 + +[Editor] +DistanceSpacing: 1.2 +BeatDivisor: 4 +GridSize: 4 +TimelineZoom: 1 + +[Metadata] +Title:My Love +TitleUnicode:My Love +Artist:Kuba Oms +ArtistUnicode:Kuba Oms +Creator:W h i t e +Version:Hard +Source:ADHD +Tags:Monthly Beatmapping Contest Electronic folk pop w_h_i_t_e +BeatmapID:397534 +BeatmapSetID:163112 + +[Difficulty] +HPDrainRate:5 +CircleSize:4 +OverallDifficulty:6 +ApproachRate:7 +SliderMultiplier:1.44 +SliderTickRate:2 + +[Events] +//Break Periods +2,69870,83770 +2,152170,158770 +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Sound Samples + +[TimingPoints] +2170,468.75,4,2,0,40,1,0 +4045,-100,4,2,0,30,0,0 +4162,-100,4,2,0,40,0,0 +5920,-100,4,2,0,30,0,0 +6037,-100,4,2,0,40,0,0 +7795,-100,4,2,0,30,0,0 +7912,-100,4,2,0,40,0,0 +9670,-100,4,2,0,40,0,0 +9787,-100,4,2,0,50,0,0 +11545,-100,4,2,0,40,0,0 +11662,-100,4,2,0,50,0,0 +13420,-100,4,2,0,40,0,0 +13537,-100,4,2,0,50,0,0 +15295,-100,4,2,0,40,0,0 +15412,-100,4,2,0,50,0,0 +17170,-100,4,2,0,40,0,0 +17287,-100,4,2,0,50,0,0 +19045,-100,4,2,0,40,0,0 +19162,-100,4,2,0,50,0,0 +20920,-100,4,2,0,40,0,0 +21037,-100,4,2,0,50,0,0 +22795,-100,4,2,0,40,0,0 +22912,-100,4,2,0,50,0,0 +24670,-100,4,2,0,70,0,0 +37560,-200,4,2,0,30,0,0 +38263,-200,4,2,0,5,0,0 +38966,-100,4,2,0,30,0,0 +39670,-100,4,2,0,70,0,0 +53732,-100,4,2,0,40,0,0 +54670,-100,4,2,0,80,0,1 +55138,-100,4,2,0,60,0,1 +55255,-100,4,2,0,80,0,1 +56076,-100,4,2,0,60,0,1 +56193,-100,4,2,0,80,0,1 +57013,-100,4,2,0,60,0,1 +57130,-100,4,2,0,80,0,1 +57951,-100,4,2,0,60,0,1 +58068,-100,4,2,0,80,0,1 +58888,-100,4,2,0,60,0,1 +59005,-100,4,2,0,80,0,1 +59826,-100,4,2,0,60,0,1 +59943,-100,4,2,0,80,0,1 +60763,-100,4,2,0,60,0,1 +60880,-100,4,2,0,80,0,1 +61701,-100,4,2,0,60,0,1 +61818,-100,4,2,0,80,0,1 +62638,-100,4,2,0,60,0,1 +62755,-100,4,2,0,80,0,1 +63576,-100,4,2,0,60,0,1 +63693,-100,4,2,0,80,0,1 +64513,-100,4,2,0,60,0,1 +64630,-100,4,2,0,80,0,1 +65451,-100,4,2,0,60,0,1 +65568,-100,4,2,0,80,0,1 +66388,-100,4,2,0,60,0,1 +66505,-100,4,2,0,80,0,1 +67326,-100,4,2,0,60,0,1 +67443,-100,4,2,0,80,0,1 +68263,-100,4,2,0,60,0,1 +68380,-100,4,2,0,80,0,1 +69201,-100,4,2,0,60,0,1 +69318,-100,4,2,0,80,0,1 +69670,-100,4,2,0,70,0,0 +84670,-100,4,2,0,70,0,0 +97560,-200,4,2,0,70,0,0 +97795,-200,4,2,0,30,0,0 +98966,-100,4,2,0,30,0,0 +99670,-100,4,2,0,70,0,0 +113732,-100,4,2,0,40,0,0 +114670,-100,4,2,0,80,0,1 +115138,-100,4,2,0,60,0,1 +115255,-100,4,2,0,80,0,1 +116076,-100,4,2,0,60,0,1 +116193,-100,4,2,0,80,0,1 +117013,-100,4,2,0,60,0,1 +117130,-100,4,2,0,80,0,1 +117951,-100,4,2,0,60,0,1 +118068,-100,4,2,0,80,0,1 +118888,-100,4,2,0,60,0,1 +119005,-100,4,2,0,80,0,1 +119826,-100,4,2,0,60,0,1 +119943,-100,4,2,0,80,0,1 +120763,-100,4,2,0,60,0,1 +120880,-100,4,2,0,80,0,1 +121701,-100,4,2,0,60,0,1 +121818,-100,4,2,0,80,0,1 +122638,-100,4,2,0,60,0,1 +122755,-100,4,2,0,80,0,1 +123576,-100,4,2,0,60,0,1 +123693,-100,4,2,0,80,0,1 +124513,-100,4,2,0,60,0,1 +124630,-100,4,2,0,80,0,1 +125451,-100,4,2,0,60,0,1 +125568,-100,4,2,0,80,0,1 +126388,-100,4,2,0,60,0,1 +126505,-100,4,2,0,80,0,1 +127326,-100,4,2,0,60,0,1 +127443,-100,4,2,0,80,0,1 +128263,-100,4,2,0,60,0,1 +128380,-100,4,2,0,80,0,1 +129201,-100,4,2,0,60,0,1 +129318,-100,4,2,0,80,0,1 +129670,-200,4,2,0,40,0,0 +144670,-133.333333333333,4,2,0,40,0,0 +159670,-133.333333333333,4,2,0,40,0,0 +163420,-133.333333333333,4,2,0,45,0,0 +163888,-125,4,2,0,50,0,0 +164357,-117.647058823529,4,2,0,55,0,0 +164826,-111.111111111111,4,2,0,60,0,0 +165295,-105.263157894737,4,2,0,65,0,0 +165763,-100,4,2,0,70,0,0 +166232,-100,4,2,0,40,0,0 +167170,-100,4,2,0,80,0,1 +167638,-100,4,2,0,60,0,1 +167755,-100,4,2,0,80,0,1 +168576,-100,4,2,0,60,0,1 +168693,-100,4,2,0,80,0,1 +169513,-100,4,2,0,60,0,1 +169630,-100,4,2,0,80,0,1 +170451,-100,4,2,0,60,0,1 +170568,-100,4,2,0,80,0,1 +171388,-100,4,2,0,60,0,1 +171505,-100,4,2,0,80,0,1 +172326,-100,4,2,0,60,0,1 +172443,-100,4,2,0,80,0,1 +173263,-100,4,2,0,60,0,1 +173380,-100,4,2,0,80,0,1 +174201,-100,4,2,0,60,0,1 +174318,-100,4,2,0,80,0,1 +175138,-100,4,2,0,60,0,1 +175255,-100,4,2,0,80,0,1 +176076,-100,4,2,0,60,0,1 +176193,-100,4,2,0,80,0,1 +177013,-100,4,2,0,60,0,1 +177130,-100,4,2,0,80,0,1 +177951,-100,4,2,0,60,0,1 +178068,-100,4,2,0,80,0,1 +178888,-100,4,2,0,60,0,1 +179005,-100,4,2,0,80,0,1 +179826,-100,4,2,0,60,0,1 +179943,-100,4,2,0,80,0,1 +180763,-100,4,2,0,60,0,1 +180880,-100,4,2,0,80,0,1 +180998,-100,4,2,0,80,0,0 +181466,-100,4,2,0,60,0,0 +181584,-100,4,2,0,80,0,0 +181935,-100,4,2,0,80,0,0 +182170,-100,4,2,0,80,0,1 +182638,-100,4,2,0,60,0,1 +182755,-100,4,2,0,80,0,1 +183576,-100,4,2,0,60,0,1 +183693,-100,4,2,0,80,0,1 +184513,-100,4,2,0,60,0,1 +184630,-100,4,2,0,80,0,1 +185451,-100,4,2,0,60,0,1 +185568,-100,4,2,0,80,0,1 +186388,-100,4,2,0,60,0,1 +186505,-100,4,2,0,80,0,1 +187326,-100,4,2,0,60,0,1 +187443,-100,4,2,0,80,0,1 +188263,-100,4,2,0,60,0,1 +188380,-100,4,2,0,80,0,1 +189201,-100,4,2,0,60,0,1 +189318,-100,4,2,0,80,0,1 +190138,-100,4,2,0,60,0,1 +190255,-100,4,2,0,80,0,1 +191076,-100,4,2,0,60,0,1 +191193,-100,4,2,0,80,0,1 +192013,-100,4,2,0,60,0,1 +192130,-100,4,2,0,80,0,1 +192951,-100,4,2,0,60,0,1 +193068,-100,4,2,0,80,0,1 +193888,-100,4,2,0,60,0,1 +194005,-100,4,2,0,80,0,1 +194826,-100,4,2,0,60,0,1 +194943,-100,4,2,0,80,0,1 +195295,-100,4,2,0,50,0,1 +195529,-100,4,2,0,52,0,1 +195646,-100,4,2,0,54,0,1 +195763,-100,4,2,0,56,0,1 +195880,-100,4,2,0,58,0,1 +195998,-100,4,2,0,60,0,1 +196115,-100,4,2,0,62,0,1 +196232,-100,4,2,0,64,0,1 +196349,-100,4,2,0,68,0,1 +196466,-100,4,2,0,70,0,1 +196584,-100,4,2,0,72,0,1 +196701,-100,4,2,0,74,0,1 +196818,-100,4,2,0,76,0,1 +196935,-100,4,2,0,78,0,1 +197052,-100,4,2,0,80,0,1 +197170,-100,4,2,0,80,0,0 +197873,-100,4,2,0,60,0,0 +197990,-100,4,2,0,80,0,0 +198341,-100,4,2,0,60,0,0 +199045,-100,4,2,0,80,0,0 +199279,-100,4,2,0,60,0,0 +199630,-100,4,2,0,80,0,0 +200216,-100,4,2,0,60,0,0 +200334,-100,4,2,0,80,0,0 +201623,-100,4,2,0,60,0,0 +201740,-100,4,2,0,80,0,0 +202326,-100,4,2,0,60,0,0 +202443,-100,4,2,0,80,0,0 +203029,-100,4,2,0,60,0,0 +203498,-100,4,2,0,80,0,0 +203966,-100,4,2,0,60,0,0 +204201,-100,4,2,0,80,0,0 +205373,-100,4,2,0,60,0,0 +205490,-100,4,2,0,80,0,0 +205841,-100,4,2,0,60,0,0 +206076,-100,4,2,0,60,0,0 +206545,-100,4,2,0,80,0,0 +206779,-100,4,2,0,60,0,0 +207130,-100,4,2,0,80,0,0 +207716,-100,4,2,0,60,0,0 +207951,-100,4,2,0,80,0,0 +209123,-100,4,2,0,60,0,0 +209240,-100,4,2,0,80,0,0 +209826,-100,4,2,0,60,0,0 +209943,-100,4,2,0,80,0,0 +210529,-100,4,2,0,60,0,0 +210880,-100,4,2,0,80,0,0 +211232,-100,4,2,0,60,0,0 +211701,-100,4,2,0,70,0,0 +212170,-100,4,2,0,80,0,0 +212873,-100,4,2,0,60,0,0 +212990,-100,4,2,0,80,0,0 +213341,-100,4,2,0,60,0,0 +213576,-100,4,2,0,60,0,0 +214045,-100,4,2,0,80,0,0 +214279,-100,4,2,0,60,0,0 +214630,-100,4,2,0,80,0,0 +215216,-100,4,2,0,60,0,0 +215451,-100,4,2,0,80,0,0 +216623,-100,4,2,0,60,0,0 +216740,-100,4,2,0,80,0,0 +217326,-100,4,2,0,60,0,0 +217443,-100,4,2,0,80,0,0 +218029,-100,4,2,0,60,0,0 +218498,-100,4,2,0,80,0,0 +218732,-100,4,2,0,50,0,0 +219670,-100,4,2,0,70,0,0 +220138,-100,4,2,0,65,0,0 +220373,-100,4,2,0,45,0,0 +220490,-100,4,2,0,65,0,0 +220607,-100,4,2,0,60,0,0 +220841,-100,4,2,0,35,0,0 +221076,-100,4,2,0,35,0,0 +221545,-100,4,2,0,50,0,0 +221779,-100,4,2,0,30,0,0 +222013,-111.111111111111,4,2,0,25,0,0 +222130,-111.111111111111,4,2,0,40,0,0 +222482,-125,4,2,0,40,0,0 +222716,-125,4,2,0,20,0,0 +222951,-100,4,2,0,15,0,0 +223420,-100,4,2,0,30,0,0 +224357,-100,4,2,0,25,0,0 +225295,-100,4,2,0,20,0,0 +226232,-100,4,2,0,15,0,0 +226701,-100,4,2,0,10,0,0 +227170,-100,4,2,0,5,0,0 + + +[Colours] + Combo1 : 17,254,176 +Combo2 : 173,255,95 +Combo3 : 255,88,100 +Combo4 : 255,94,55 + +[HitObjects] +320,256,2170,6,0,P|256:284|192:256,1,144,4|0,0:0|0:0,0:0:0:0: +144,184,2873,1,0,0:0:0:0: +108,260,3107,2,0,P|112:296|100:336,1,72 +28,288,3576,2,0,P|24:252|36:212,1,72,0|0,0:0|0:0,0:0:0:0: +76,140,4045,6,0,L|220:136,1,144,4|0,0:0|0:0,0:0:0:0: +292,88,4748,1,0,0:0:0:0: +292,88,4982,2,0,P|304:120|300:168,1,72 +388,168,5451,2,0,P|396:133|416:103,1,72,0|0,0:0|0:0,0:0:0:0: +472,172,5920,6,0,B|470:200|457:222|457:222|488:256|476:308,1,144,4|0,0:0|0:0,0:0:0:0: +396,280,6623,1,0,0:0:0:0: +324,328,6857,2,0,P|288:332|252:324,1,72 +180,280,7326,2,0,L|108:284,1,72,0|0,0:0|0:0,0:0:0:0: +256,192,7795,12,0,9670,0:0:0:0: +428,212,10138,1,0,0:0:0:0: +292,320,10607,1,0,0:0:0:0: +184,184,11076,2,0,L|112:180,1,72,0|0,0:0|0:0,0:0:0:0: +24,172,11545,5,6,0:0:0:0: +160,280,12013,1,0,0:0:0:0: +268,144,12482,1,0,0:0:0:0: +132,36,12951,2,0,L|204:32,1,72,0|0,0:0|0:0,0:0:0:0: +284,60,13420,6,0,P|340:100|344:180,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0: +268,144,14591,1,0,0:0:0:0: +284,228,14826,2,0,P|316:248|364:252,1,72,0|0,0:0|0:0,0:0:0:0: +436,248,15295,6,0,P|372:272|344:340,1,144,6|2,0:0|0:0,0:0:0:0: +168,338,16232,2,0,P|141:273|76:248,1,144,2|2,0:0|0:0,0:0:0:0: +4,296,16935,1,0,0:0:0:0: +80,336,17170,5,6,0:0:0:0: +44,168,17638,1,0,0:0:0:0: +212,128,18107,1,0,0:0:0:0: +248,296,18576,2,0,P|284:288|320:292,1,72,0|0,0:0|0:0,0:0:0:0: +400,324,19045,5,6,0:0:0:0: +280,200,19513,1,0,0:0:0:0: +368,52,19982,1,0,0:0:0:0: +488,176,20451,2,0,P|452:168|416:172,1,72,0|0,0:0|0:0,0:0:0:0: +336,200,20920,6,0,P|284:216|200:192,1,144,6|0,0:0|0:0,0:0:0:0: +200,192,21857,2,0,L|204:264,1,72,0|0,0:3|0:0,0:0:0:0: +117,244,22326,2,0,L|120:172,1,72,0|0,0:0|0:0,0:0:0:0: +40,152,22795,6,0,L|28:296,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0: +152,24,24201,1,0,0:0:0:0: +220,76,24435,1,0,3:0:0:0: +304,56,24670,6,0,P|288:120|296:196,1,144,4|2,0:3|0:3,0:0:0:0: +344,268,25373,1,0,0:0:0:0: +416,316,25607,2,0,P|452:312|508:316,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +244,344,26545,6,0,P|176:356|108:328,1,144,4|2,0:3|0:3,0:0:0:0: +60,256,27248,1,0,0:0:0:0: +36,172,27482,2,0,L|40:100,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +188,252,28420,6,0,P|192:184|196:100,1,144,4|2,0:3|0:3,0:0:0:0: +140,40,29123,1,0,0:0:0:0: +140,40,29357,2,0,B|172:16|220:24|220:24|288:36,1,144,0|2,0:0|0:3,0:0:0:0: +364,52,30060,1,0,0:0:0:0: +308,116,30295,6,0,B|300:168|300:168|328:256,1,144,4|2,0:3|0:3,0:0:0:0: +340,340,30998,1,0,0:0:0:0: +260,308,31232,2,0,L|188:304,1,72,0|2,0:0|0:3,0:0:0:0: +100,296,31701,1,2,0:3:0:0: +136,374,31935,1,0,0:0:0:0: +152,224,32170,6,0,P|160:152|132:88,1,144,4|2,0:3|0:3,0:0:0:0: +56,48,32873,1,0,0:0:0:0: +60,136,33107,2,0,L|56:208,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +224,76,34045,6,0,P|289:104|360:96,1,144,4|2,0:3|0:3,0:0:0:0: +432,48,34748,1,0,0:0:0:0: +440,132,34982,2,0,B|432:156|432:156|436:204,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +448,304,35920,6,0,B|412:315|380:292|380:292|348:269|312:280,1,144,4|2,0:3|0:3,0:0:0:0: +332,364,36623,1,0,0:0:0:0: +247,339,36857,2,0,P|230:308|225:273,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +312,280,37560,6,0,L|316:172,1,108 +134,35,38966,5,0,0:0:0:0: +72,96,39201,2,0,P|119:119|171:111,1,108,0|0,0:0|0:0,0:0:0:0: +192,100,39670,6,0,L|200:172,1,72,4|2,0:0|0:0,0:0:0:0: +147,240,40138,2,0,P|133:272|132:308,1,72,0|2,1:0|0:0,0:0:0:0: +216,292,40607,2,0,B|260:308|260:308|356:292,1,144,4|0,2:3|1:0,1:0:0:0: +356,292,41310,1,2,0:0:0:0: +436,327,41545,6,0,P|441:292|435:257,1,72,4|2,0:3|0:0,0:0:0:0: +364,204,42013,2,0,P|336:144|352:68,1,144,0|4,1:0|2:3,1:0:0:0: +404,0,42716,1,2,0:0:0:0: +440,80,42951,2,0,B|464:84|464:84|512:80,1,72,0|2,1:0|0:0,0:0:0:0: +351,71,43420,6,0,B|296:68|296:68|268:76|268:76|196:72,1,144,4|0,2:3|1:0,1:0:0:0: +120,68,44123,1,2,0:0:0:0: +160,144,44357,2,0,P|172:180|168:232,1,72,4|2,0:3|0:0,0:0:0:0: +76,264,44826,2,0,P|76:228|88:194,1,72,0|2,1:0|0:0,0:0:0:0: +160,144,45295,5,4,0:3:0:0: +244,164,45529,1,2,0:0:0:0: +268,248,45763,2,0,L|344:252,1,72,0|2,1:0|0:0,0:0:0:0: +408,156,46232,2,0,L|336:159,1,72,4|2,0:3|0:0,0:0:0:0: +212,72,46701,2,0,L|288:76,1,72,0|2,1:0|0:0,0:0:0:0: +400,72,47170,6,0,P|464:96|488:172,1,144,4|0,2:0|1:0,1:0:0:0: +476,248,47873,1,2,0:0:0:0: +436,324,48107,2,0,L|284:320,1,144,4|0,2:3|1:0,1:0:0:0: +204,316,48810,1,2,0:0:0:0: +127,355,49045,6,0,P|120:321|124:285,1,72,4|2,0:3|0:0,0:0:0:0: +192,232,49513,2,0,L|335:228,1,144,0|4,1:0|2:3,1:0:0:0: +412,188,50216,1,2,0:0:0:0: +444,108,50451,2,0,P|452:72|448:36,1,72,0|2,1:0|0:0,0:0:0:0: +368,68,50920,6,0,B|332:79|300:56|300:56|268:33|232:44,1,144,4|0,2:3|1:0,1:0:0:0: +152,76,51623,1,2,0:0:0:0: +76,116,51857,2,0,L|80:268,1,144,4|0,2:3|1:0,1:0:0:0: +80,260,52560,1,2,0:0:0:0: +8,308,52795,6,0,P|34:334|69:346,1,72,4|2,0:3|0:0,0:0:0:0: +148,312,53263,2,0,P|163:278|162:241,1,72,0|2,1:0|0:0,0:0:0:0: +156,156,53732,5,0,3:0:0:0: +156,156,53966,1,2,0:0:0:0: +236,196,54201,2,0,L|312:192,1,72,8|0,0:3|0:0,0:0:0:0: +368,256,54670,6,0,P|392:216|352:116,1,144,4|2,0:0|1:2,0:0:0:0: +288,92,55373,1,0,0:0:0:0: +360,40,55607,2,0,L|432:36,1,72,4|0,0:3|3:0,0:0:0:0: +288,92,56076,2,0,L|216:88,1,72,2|0,1:2|0:0,0:0:0:0: +132,72,56545,6,0,P|172:88|200:184,1,144,4|2,0:3|1:2,0:0:0:0: +143,241,57248,1,0,0:0:0:0: +65,202,57482,2,0,P|87:174|119:157,1,72,4|0,0:3|3:0,0:0:0:0: +132,324,57951,2,0,P|98:312|72:288,1,72,2|0,1:2|0:0,0:0:0:0: +143,241,58420,6,0,L|288:240,1,144,4|2,0:3|1:2,0:0:0:0: +372,240,59123,1,0,0:0:0:0: +330,314,59357,2,0,P|318:350|322:390,1,72,4|0,0:3|3:0,0:0:0:0: +452,264,59826,2,0,P|453:228|442:194,1,72,2|0,1:2|0:0,0:0:0:0: +384,128,60295,6,0,B|336:144|336:144|244:128,1,144,4|2,0:3|1:2,0:0:0:0: +164,160,60998,2,0,P|160:116|168:88,1,72,0|4,0:0|0:3,0:0:0:0: +244,128,61466,2,0,P|248:172|240:200,1,72,0|2,3:0|1:2,0:0:0:0: +168,248,61935,1,0,0:0:0:0: +120,320,62170,6,0,P|196:328|252:272,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: +80,244,63341,1,0,3:0:0:0: +100,160,63576,2,0,L|24:156,1,72,2|0,1:2|0:0,0:0:0:0: +180,128,64045,6,0,P|249:138|304:94,1,144,4|2,0:3|1:2,0:0:0:0: +226,57,64748,1,0,0:0:0:0: +304,94,64982,2,0,L|300:166,1,72,4|0,0:3|3:0,0:0:0:0: +377,203,65451,2,0,L|388:132,1,72,2|0,1:2|0:0,0:0:0:0: +468,180,65920,6,0,L|432:328,1,144,4|2,0:3|1:2,0:0:0:0: +276,252,66857,2,0,P|208:248|140:280,1,144,4|2,0:3|1:2,0:0:0:0: +84,344,67560,1,0,0:0:0:0: +56,260,67795,6,0,L|52:188,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +168,128,68732,2,0,L|172:56,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +244,168,69435,1,0,0:0:0:0: +332,164,69670,1,4,0:3:0:0: +208,328,84670,6,0,P|224:264|216:188,1,144,4|2,0:3|0:3,0:0:0:0: +168,116,85373,1,0,0:0:0:0: +96,68,85607,2,0,P|60:72|4:68,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +268,40,86545,6,0,P|336:28|404:56,1,144,4|2,0:3|0:3,0:0:0:0: +452,128,87248,1,0,0:0:0:0: +476,212,87482,2,0,L|472:284,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +324,132,88420,6,0,P|320:200|316:284,1,144,4|2,0:3|0:3,0:0:0:0: +372,344,89123,1,0,0:0:0:0: +372,344,89357,2,0,B|340:368|292:360|292:360|224:348,1,144,0|2,0:0|0:3,0:0:0:0: +148,332,90060,1,0,0:0:0:0: +204,268,90295,6,0,B|212:216|212:216|184:128,1,144,4|2,0:3|0:3,0:0:0:0: +172,44,90998,1,0,0:0:0:0: +252,76,91232,2,0,L|324:80,1,72,0|2,0:0|0:3,0:0:0:0: +412,88,91701,1,2,0:3:0:0: +377,9,91935,1,0,0:0:0:0: +360,160,92170,6,0,P|352:232|380:296,1,144,4|2,0:3|0:3,0:0:0:0: +456,336,92873,1,0,0:0:0:0: +452,248,93107,2,0,L|456:176,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +288,308,94045,6,0,P|223:280|152:288,1,144,4|2,0:3|0:3,0:0:0:0: +80,336,94748,1,0,0:0:0:0: +72,252,94982,2,0,B|80:228|80:228|76:180,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +64,80,95920,6,0,B|100:69|132:92|132:92|164:115|200:104,1,144,4|2,0:3|0:3,0:0:0:0: +180,20,96623,1,0,0:0:0:0: +265,45,96857,2,0,P|282:76|287:111,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: +200,104,97560,1,0,0:0:0:0: +200,104,97677,1,0,0:0:0:0: +200,104,97795,6,0,B|196:142|217:166|217:166|176:180|160:220,1,144,4|0,0:3|0:0,0:0:0:0: +240,248,98966,5,0,0:0:0:0: +202,325,99201,2,0,P|254:333|301:309,1,108,0|0,0:0|0:0,0:0:0:0: +315,292,99670,6,0,L|323:220,1,72,4|2,0:0|0:0,0:0:0:0: +365,144,100138,2,0,P|379:112|380:76,1,72,0|2,1:0|0:0,0:0:0:0: +296,92,100607,2,0,B|252:76|252:76|156:92,1,144,4|0,2:3|1:0,1:0:0:0: +156,92,101310,1,2,0:0:0:0: +76,57,101545,6,0,P|71:92|77:127,1,72,4|2,0:3|0:0,0:0:0:0: +148,180,102013,2,0,P|176:240|160:316,1,144,0|4,1:0|2:3,1:0:0:0: +108,384,102716,1,2,0:0:0:0: +72,304,102951,2,0,B|48:300|48:300|0:304,1,72,0|2,1:0|0:0,0:0:0:0: +161,313,103420,6,0,B|216:316|216:316|244:308|244:308|316:312,1,144,4|0,2:3|1:0,1:0:0:0: +392,316,104123,1,2,0:0:0:0: +352,240,104357,2,0,P|340:204|344:152,1,72,4|2,0:3|0:0,0:0:0:0: +436,120,104826,2,0,P|436:156|424:190,1,72,0|2,1:0|0:0,0:0:0:0: +352,240,105295,5,4,0:3:0:0: +268,220,105529,1,2,0:0:0:0: +244,136,105763,2,0,L|168:132,1,72,0|2,1:0|0:0,0:0:0:0: +104,228,106232,2,0,L|176:225,1,72,4|2,0:3|0:0,0:0:0:0: +300,312,106701,2,0,L|224:308,1,72,0|2,1:0|0:0,0:0:0:0: +112,312,107170,6,0,P|48:288|24:212,1,144,4|0,2:0|1:0,1:0:0:0: +36,136,107873,1,2,0:0:0:0: +76,60,108107,2,0,L|228:64,1,144,4|0,2:3|1:0,1:0:0:0: +308,68,108810,1,2,0:0:0:0: +385,29,109045,6,0,P|392:63|388:99,1,72,4|2,0:3|0:0,0:0:0:0: +320,152,109513,2,0,L|177:156,1,144,0|4,1:0|2:3,1:0:0:0: +100,196,110216,1,2,0:0:0:0: +68,276,110451,2,0,P|60:312|64:348,1,72,0|2,1:0|0:0,0:0:0:0: +144,316,110920,6,0,B|180:305|212:328|212:328|244:351|280:340,1,144,4|0,2:3|1:0,1:0:0:0: +360,308,111623,1,2,0:0:0:0: +436,268,111857,2,0,L|432:116,1,144,4|0,2:3|1:0,1:0:0:0: +432,124,112560,1,2,0:0:0:0: +504,76,112795,6,0,P|478:50|443:38,1,72,4|2,0:3|0:0,0:0:0:0: +364,72,113263,2,0,P|349:106|350:143,1,72,0|2,1:0|0:0,0:0:0:0: +356,228,113732,5,0,3:0:0:0: +356,228,113966,1,2,0:0:0:0: +276,188,114201,2,0,L|200:192,1,72,8|0,0:3|0:0,0:0:0:0: +144,128,114670,6,0,P|120:168|160:268,1,144,4|2,0:0|1:2,0:0:0:0: +224,292,115373,1,0,0:0:0:0: +152,344,115607,2,0,L|80:348,1,72,4|0,0:3|3:0,0:0:0:0: +224,292,116076,2,0,L|296:296,1,72,2|0,1:2|0:0,0:0:0:0: +380,312,116545,6,0,P|340:296|312:200,1,144,4|2,0:3|1:2,0:0:0:0: +369,143,117248,1,0,0:0:0:0: +447,182,117482,2,0,P|425:210|393:227,1,72,4|0,0:3|3:0,0:0:0:0: +380,60,117951,2,0,P|414:72|440:96,1,72,2|0,1:2|0:0,0:0:0:0: +369,143,118420,6,0,L|224:144,1,144,4|2,0:3|1:2,0:0:0:0: +140,144,119123,1,0,0:0:0:0: +182,70,119357,2,0,P|194:34|190:-6,1,72,4|0,0:3|3:0,0:0:0:0: +60,120,119826,2,0,P|59:156|70:190,1,72,2|0,1:2|0:0,0:0:0:0: +128,256,120295,6,0,B|176:240|176:240|268:256,1,144,4|2,0:3|1:2,0:0:0:0: +348,224,120998,2,0,P|352:268|344:296,1,72,0|4,0:0|0:3,0:0:0:0: +268,256,121466,2,0,P|264:212|272:184,1,72,0|2,3:0|1:2,0:0:0:0: +344,136,121935,1,0,0:0:0:0: +392,64,122170,6,0,P|316:56|260:112,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: +432,140,123341,1,0,3:0:0:0: +412,224,123576,2,0,L|488:228,1,72,2|0,1:2|0:0,0:0:0:0: +332,256,124045,6,0,P|263:246|208:290,1,144,4|2,0:3|1:2,0:0:0:0: +286,327,124748,1,0,0:0:0:0: +208,290,124982,2,0,L|212:218,1,72,4|0,0:3|3:0,0:0:0:0: +135,181,125451,2,0,L|124:252,1,72,2|0,1:2|0:0,0:0:0:0: +44,204,125920,6,0,L|80:56,1,144,4|2,0:3|1:2,0:0:0:0: +236,132,126857,2,0,P|304:136|372:104,1,144,4|2,0:3|1:2,0:0:0:0: +428,40,127560,1,0,0:0:0:0: +456,124,127795,6,0,L|460:196,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +344,256,128732,2,0,L|340:328,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +268,216,129435,1,0,0:0:0:0: +180,220,129670,5,4,2:0:0:0: +256,40,130373,1,2,0:0:0:0: +64,68,131076,1,2,0:0:0:0: +92,136,131310,1,0,0:0:0:0: +64,204,131545,6,0,L|60:288,1,72 +31,343,132248,2,0,P|86:345|127:309,1,108 +332,220,133420,5,2,0:0:0:0: +256,40,134123,1,2,0:0:0:0: +448,68,134826,1,2,0:0:0:0: +420,136,135060,1,0,0:0:0:0: +448,204,135295,6,0,L|452:288,1,72,2|0,0:0|0:0,0:0:0:0: +480,343,135998,2,0,P|426:345|385:309,1,108 +256,192,137170,5,2,0:0:0:0: +156,360,137873,1,2,0:0:0:0: +356,360,138576,2,0,L|352:308,1,36,2|0,0:0|0:0,0:0:0:0: +304,268,139045,6,0,P|336:253|372:252,1,72 +448,260,139748,2,0,L|444:152,1,108 +256,192,140920,5,2,0:0:0:0: +356,24,141623,1,2,0:0:0:0: +156,24,142326,2,0,L|160:72,1,36,2|0,0:0|0:0,0:0:0:0: +208,116,142795,6,0,P|176:131|140:132,1,72,2|0,0:0|0:0,0:0:0:0: +64,124,143498,2,0,L|68:232,1,108 +68,232,144670,5,4,0:3:0:0: +216,320,145138,1,4,0:3:0:0: +304,172,145607,1,4,0:3:0:0: +156,84,146075,1,4,0:3:0:0: +296,320,146545,5,4,0:3:0:0: +208,172,147013,1,4,0:3:0:0: +356,84,147482,1,4,0:3:0:0: +444,232,147950,1,4,0:3:0:0: +296,320,148420,6,0,P|252:328|192:296,2,108.000004119873,4|4|4,0:3|0:3|0:3,0:0:0:0: +260,248,149591,1,0,0:0:0:0: +320,196,149826,2,0,L|316:140,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0: +120,236,159670,6,0,L|176:232,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0: +160,152,160138,2,0,L|104:156,1,54.0000020599366,2|0,0:0|0:0,0:0:0:0: +240,180,160607,2,0,P|292:188|344:172,1,108.000004119873,4|2,0:3|0:0,3:0:0:0: +408,120,161310,1,0,3:0:0:0: +424,200,161545,6,0,L|420:256,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0: +376,320,162013,2,0,P|396:328|480:304,2,108.000004119873,2|6|2,2:0|0:3|2:0,3:0:0:0: +312,268,163185,1,0,0:0:0:0: +296,348,163420,6,0,L|240:344,1,54.0000020599366,4|0,3:0|3:0,0:0:0:0: +160,320,163888,2,0,L|100:316,1,57.6,4|0,3:0|3:0,0:0:0:0: +64,232,164357,6,0,L|128:228,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0: +204,200,164825,2,0,L|268:196,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0: +232,108,165295,6,0,L|164:104,1,68.399998173523,4|0,3:0|3:0,0:0:0:0: +80,84,165763,2,0,L|4:80,1,72,4|0,3:0|3:0,0:0:0:0: +324,120,167170,6,0,P|388:128|456:92,1,144,4|2,0:0|1:2,0:0:0:0: +496,168,167873,1,0,0:0:0:0: +496,168,168107,2,0,P|484:204|488:256,1,72,4|0,0:3|3:0,0:0:0:0: +408,296,168576,2,0,P|398:261|378:231,1,72,2|0,1:2|0:0,0:0:0:0: +296,200,169045,6,0,B|228:228|156:204,1,144,4|2,0:3|1:2,0:0:0:0: +84,156,169748,1,0,0:0:0:0: +80,244,169982,2,0,L|76:316,1,72,4|0,0:3|3:0,0:0:0:0: +170,274,170451,2,0,L|156:204,1,72,2|0,1:2|0:0,0:0:0:0: +216,140,170920,6,0,L|284:276,1,144,4|2,0:3|1:2,0:0:0:0: +320,344,171623,1,0,0:0:0:0: +372,276,171857,2,0,P|366:240|349:207,1,72,4|0,0:3|3:0,0:0:0:0: +312,132,172326,2,0,L|276:60,1,72,2|0,1:2|0:0,0:0:0:0: +208,20,172795,6,0,P|272:36|348:12,1,144,4|2,0:3|1:2,0:0:0:0: +424,48,173498,2,0,L|412:132,1,72,0|4,0:0|0:3,0:0:0:0: +484,168,173966,2,0,L|472:252,1,72,0|2,3:0|1:2,0:0:0:0: +400,280,174435,1,0,0:0:0:0: +346,348,174670,6,0,P|414:363|472:324,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: +312,268,175841,1,0,3:0:0:0: +256,336,176076,2,0,L|184:332,1,72,2|0,1:2|0:0,0:0:0:0: +80,244,176545,6,0,B|140:248|140:248|164:244|164:244|223:247,1,144,4|2,0:3|1:2,0:0:0:0: +312,268,177248,1,0,0:0:0:0: +224,247,177482,2,0,P|240:215|272:187,1,72,4|0,0:3|3:0,0:0:0:0: +204,131,177951,2,0,P|233:111|275:103,1,72,2|0,1:2|0:0,0:0:0:0: +240,23,178420,6,0,B|280:15|316:35|316:35|376:71,1,144,4|2,0:3|1:2,0:0:0:0: +399,236,179357,2,0,B|359:244|323:224|323:224|263:188,1,144,4|2,0:3|1:2,0:0:0:0: +204,132,180060,1,0,0:0:0:0: +184,216,180295,6,0,L|188:288,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +120,156,180998,1,0,0:0:0:0: +56,96,181232,2,0,L|60:24,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: +36,180,181935,1,0,0:0:0:0: +100,240,182170,6,0,P|144:300|116:380,2,144,4|2|4,0:0|1:2|0:3,0:0:0:0: +60,316,183341,1,0,0:0:0:0: +220,352,183576,2,0,L|308:348,1,72,2|0,1:2|0:0,0:0:0:0: +396,264,184045,6,0,B|336:268|336:268|312:264|312:264|253:267,1,144,4|2,0:3|1:2,0:0:0:0: +253,267,184748,1,0,0:0:0:0: +268,180,184982,2,0,L|339:177,1,72,4|0,0:3|0:0,0:0:0:0: +164,280,185451,2,0,L|92:282,1,72,2|0,1:2|0:0,0:0:0:0: +52,208,185920,6,0,P|8:268|32:344,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: +140,212,187091,1,0,0:0:0:0: +92,284,187326,2,0,P|104:316|100:368,1,72,2|0,1:2|0:0,0:0:0:0: +52,208,187795,6,0,P|48:136|76:72,1,144,4|2,0:3|1:2,0:0:0:0: +160,52,188498,2,0,P|188:28|220:16,1,72,0|4,0:0|0:3,0:0:0:0: +232,100,188966,2,0,P|268:93|301:98,1,72,0|2,0:0|1:2,0:0:0:0: +372,152,189435,1,0,0:0:0:0: +420,224,189670,6,0,P|428:296|400:360,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: +372,152,190841,1,0,0:0:0:0: +392,68,191076,2,0,L|465:64,1,72,2|0,1:2|0:0,0:0:0:0: +304,92,191545,6,0,P|236:104|168:76,1,144,4|2,0:3|1:2,0:0:0:0: +108,12,192248,1,0,0:0:0:0: +168,76,192482,2,0,L|172:152,1,72,4|0,0:3|0:0,0:0:0:0: +80,136,192951,2,0,L|101:204,1,72,2|0,1:2|0:0,0:0:0:0: +12,220,193420,6,0,B|50:279|50:279|80:300|120:292,1,144,4|2,0:3|1:2,0:0:0:0: +284,232,194357,2,0,B|320:221|352:244|352:244|384:267|420:256,1,144,4|2,0:3|1:2,0:0:0:0: +488,200,195060,1,0,0:0:0:0: +507,284,195295,6,0,P|492:315|464:338,1,72,4|0,0:0|0:0,0:0:0:0: +380,356,195763,2,0,L|236:352,1,144,0|4,1:0|0:3,0:0:0:0: +152,328,196466,1,0,3:0:0:0: +64,336,196701,2,0,P|29:325|4:300,1,72,0|0,1:0|0:0,0:0:0:0: +76,252,197170,6,0,P|108:188|96:116,1,144,4|0,0:0|1:0,0:0:0:0: +36,56,197873,1,2,0:0:0:0: +120,32,198107,2,0,L|192:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +248,152,199045,6,0,P|280:168|304:196,1,72,4|2,0:3|0:0,0:0:0:0: +336,277,199513,2,0,P|306:296|269:303,1,72,2|0,1:2|0:0,0:0:0:0: +183,290,199982,2,0,P|180:254|193:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: +436,252,200920,6,0,P|404:188|416:116,1,144,4|0,0:3|1:0,0:0:0:0: +476,56,201623,1,2,0:0:0:0: +392,32,201857,2,0,L|320:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0: +264,152,202795,6,0,P|232:168|208:196,1,72,4|2,0:3|0:0,0:0:0:0: +176,277,203263,2,0,P|205:296|242:303,1,72,2|0,1:2|0:0,0:0:0:0: +329,290,203732,2,0,P|331:254|318:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: +72,324,204670,6,0,B|60:272|60:272|76:180,1,144,4|0,0:0|1:0,0:0:0:0: +92,96,205373,1,2,0:0:0:0: +8,124,205607,2,0,P|5:88|14:53,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +168,192,206545,6,0,P|200:174|237:173,1,72,4|2,0:3|0:0,0:0:0:0: +320,160,207013,2,0,P|318:196|301:229,1,72,2|0,1:2|0:0,0:0:0:0: +272,307,207482,2,0,P|240:287|221:256,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: +440,324,208420,6,0,B|452:272|452:272|436:180,1,144,4|0,0:3|1:0,0:0:0:0: +420,96,209123,1,2,0:0:0:0: +504,124,209357,2,0,P|507:88|498:53,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0: +344,192,210295,6,0,P|311:174|274:173,1,72,4|2,0:3|0:0,0:0:0:0: +190,156,210763,2,0,P|191:192|208:225,1,72,2|0,1:2|0:0,0:0:0:0: +288,256,211232,1,4,0:3:0:0: +132,332,211701,1,0,1:0:0:0: +28,192,212170,6,0,P|16:120|44:56,1,144,4|0,0:0|1:0,0:0:0:0: +120,16,212873,1,2,0:0:0:0: +204,32,213107,2,0,L|304:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +192,204,214045,6,0,P|196:240|216:272,1,72,4|2,0:3|0:0,0:0:0:0: +298,241,214513,2,0,P|327:219|345:186,1,72,6|0,1:2|0:0,0:0:0:0: +280,132,214982,2,0,P|246:117|209:118,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: +484,192,215920,6,0,P|496:120|468:56,1,144,4|0,0:3|1:0,0:0:0:0: +392,16,216623,1,2,0:0:0:0: +308,32,216857,2,0,L|208:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0: +320,204,217795,6,0,P|316:240|296:272,1,72,4|2,0:3|0:0,0:0:0:0: +213,241,218263,2,0,P|184:219|166:186,1,72,2|0,1:2|0:0,0:0:0:0: +232,132,218732,2,0,B|260:112|300:116|300:116|384:128,1,144,4|0,0:3|1:0,0:0:0:0: +348,336,219670,6,0,B|320:356|280:352|280:352|196:340,1,144,4|0,0:0|1:0,0:0:0:0: +124,328,220373,1,2,0:0:0:0: +54,276,220607,2,0,P|41:308|39:345,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: +156,80,221545,6,0,L|251:94,1,72,4|2,0:3|0:0,0:0:0:0: +212,169,222013,2,0,L|148:160,1,64.799998022461,2|0,1:2|0:0,0:0:0:0: +140,240,222482,2,0,L|216:252,2,57.6,4|2|0,0:3|0:0|1:0,0:0:0:0: +256,192,223420,12,0,227170,0:0:0:0: +"; + } +} diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index af482dc250..68bb3f6dd9 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -4,11 +4,17 @@ using osu.Framework.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; +using osu.Game.Rulesets; namespace osu.Game.Tests.Beatmaps { public class TestWorkingBeatmap : WorkingBeatmap { + public TestWorkingBeatmap(RulesetInfo ruleset) + : this(new TestBeatmap(ruleset)) + { + } + public TestWorkingBeatmap(Beatmap beatmap) : base(beatmap.BeatmapInfo) { @@ -16,7 +22,6 @@ namespace osu.Game.Tests.Beatmaps } private readonly Beatmap beatmap; - protected override Beatmap GetBeatmap() => beatmap; protected override Texture GetBackground() => null; protected override Track GetTrack() => new TrackVirtual(); diff --git a/osu.Game/Tests/Visual/TestCasePlayer.cs b/osu.Game/Tests/Visual/TestCasePlayer.cs index d835adb54f..b7c66a37e5 100644 --- a/osu.Game/Tests/Visual/TestCasePlayer.cs +++ b/osu.Game/Tests/Visual/TestCasePlayer.cs @@ -1,9 +1,7 @@ // 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 System.Text; using osu.Framework.Allocation; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; @@ -59,24 +57,13 @@ namespace osu.Game.Tests.Visual } } - protected virtual Beatmap CreateBeatmap() - { - Beatmap beatmap; - - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) - using (var reader = new StreamReader(stream)) - beatmap = Game.Beatmaps.Formats.Decoder.GetDecoder(reader).Decode(reader); - - return beatmap; - } + protected virtual Beatmap CreateBeatmap(Ruleset ruleset) => new TestBeatmap(ruleset.RulesetInfo); private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); private Player loadPlayerFor(Ruleset r) { - var beatmap = CreateBeatmap(); - - beatmap.BeatmapInfo.Ruleset = r.RulesetInfo; + var beatmap = CreateBeatmap(r); working = new TestWorkingBeatmap(beatmap); working.Mods.Value = new[] { r.GetAllMods().First(m => m is ModNoFail) }; @@ -107,699 +94,5 @@ namespace osu.Game.Tests.Visual AllowLeadIn = false, AllowResults = false, }; - - private const string test_beatmap_data = - @"osu file format v14 - -[General] -AudioLeadIn: 500 -PreviewTime: 53498 -Countdown: 0 -SampleSet: Soft -StackLeniency: 0.7 -Mode: 0 -LetterboxInBreaks: 0 -WidescreenStoryboard: 1 - -[Editor] -DistanceSpacing: 1.2 -BeatDivisor: 4 -GridSize: 4 -TimelineZoom: 1 - -[Metadata] -Title:My Love -TitleUnicode:My Love -Artist:Kuba Oms -ArtistUnicode:Kuba Oms -Creator:W h i t e -Version:Hard -Source:ADHD -Tags:Monthly Beatmapping Contest Electronic folk pop w_h_i_t_e -BeatmapID:397534 -BeatmapSetID:163112 - -[Difficulty] -HPDrainRate:5 -CircleSize:4 -OverallDifficulty:6 -ApproachRate:7 -SliderMultiplier:1.44 -SliderTickRate:2 - -[Events] -//Break Periods -2,69870,83770 -2,152170,158770 -//Storyboard Layer 0 (Background) -//Storyboard Layer 1 (Fail) -//Storyboard Layer 2 (Pass) -//Storyboard Layer 3 (Foreground) -//Storyboard Sound Samples - -[TimingPoints] -2170,468.75,4,2,0,40,1,0 -4045,-100,4,2,0,30,0,0 -4162,-100,4,2,0,40,0,0 -5920,-100,4,2,0,30,0,0 -6037,-100,4,2,0,40,0,0 -7795,-100,4,2,0,30,0,0 -7912,-100,4,2,0,40,0,0 -9670,-100,4,2,0,40,0,0 -9787,-100,4,2,0,50,0,0 -11545,-100,4,2,0,40,0,0 -11662,-100,4,2,0,50,0,0 -13420,-100,4,2,0,40,0,0 -13537,-100,4,2,0,50,0,0 -15295,-100,4,2,0,40,0,0 -15412,-100,4,2,0,50,0,0 -17170,-100,4,2,0,40,0,0 -17287,-100,4,2,0,50,0,0 -19045,-100,4,2,0,40,0,0 -19162,-100,4,2,0,50,0,0 -20920,-100,4,2,0,40,0,0 -21037,-100,4,2,0,50,0,0 -22795,-100,4,2,0,40,0,0 -22912,-100,4,2,0,50,0,0 -24670,-100,4,2,0,70,0,0 -37560,-200,4,2,0,30,0,0 -38263,-200,4,2,0,5,0,0 -38966,-100,4,2,0,30,0,0 -39670,-100,4,2,0,70,0,0 -53732,-100,4,2,0,40,0,0 -54670,-100,4,2,0,80,0,1 -55138,-100,4,2,0,60,0,1 -55255,-100,4,2,0,80,0,1 -56076,-100,4,2,0,60,0,1 -56193,-100,4,2,0,80,0,1 -57013,-100,4,2,0,60,0,1 -57130,-100,4,2,0,80,0,1 -57951,-100,4,2,0,60,0,1 -58068,-100,4,2,0,80,0,1 -58888,-100,4,2,0,60,0,1 -59005,-100,4,2,0,80,0,1 -59826,-100,4,2,0,60,0,1 -59943,-100,4,2,0,80,0,1 -60763,-100,4,2,0,60,0,1 -60880,-100,4,2,0,80,0,1 -61701,-100,4,2,0,60,0,1 -61818,-100,4,2,0,80,0,1 -62638,-100,4,2,0,60,0,1 -62755,-100,4,2,0,80,0,1 -63576,-100,4,2,0,60,0,1 -63693,-100,4,2,0,80,0,1 -64513,-100,4,2,0,60,0,1 -64630,-100,4,2,0,80,0,1 -65451,-100,4,2,0,60,0,1 -65568,-100,4,2,0,80,0,1 -66388,-100,4,2,0,60,0,1 -66505,-100,4,2,0,80,0,1 -67326,-100,4,2,0,60,0,1 -67443,-100,4,2,0,80,0,1 -68263,-100,4,2,0,60,0,1 -68380,-100,4,2,0,80,0,1 -69201,-100,4,2,0,60,0,1 -69318,-100,4,2,0,80,0,1 -69670,-100,4,2,0,70,0,0 -84670,-100,4,2,0,70,0,0 -97560,-200,4,2,0,70,0,0 -97795,-200,4,2,0,30,0,0 -98966,-100,4,2,0,30,0,0 -99670,-100,4,2,0,70,0,0 -113732,-100,4,2,0,40,0,0 -114670,-100,4,2,0,80,0,1 -115138,-100,4,2,0,60,0,1 -115255,-100,4,2,0,80,0,1 -116076,-100,4,2,0,60,0,1 -116193,-100,4,2,0,80,0,1 -117013,-100,4,2,0,60,0,1 -117130,-100,4,2,0,80,0,1 -117951,-100,4,2,0,60,0,1 -118068,-100,4,2,0,80,0,1 -118888,-100,4,2,0,60,0,1 -119005,-100,4,2,0,80,0,1 -119826,-100,4,2,0,60,0,1 -119943,-100,4,2,0,80,0,1 -120763,-100,4,2,0,60,0,1 -120880,-100,4,2,0,80,0,1 -121701,-100,4,2,0,60,0,1 -121818,-100,4,2,0,80,0,1 -122638,-100,4,2,0,60,0,1 -122755,-100,4,2,0,80,0,1 -123576,-100,4,2,0,60,0,1 -123693,-100,4,2,0,80,0,1 -124513,-100,4,2,0,60,0,1 -124630,-100,4,2,0,80,0,1 -125451,-100,4,2,0,60,0,1 -125568,-100,4,2,0,80,0,1 -126388,-100,4,2,0,60,0,1 -126505,-100,4,2,0,80,0,1 -127326,-100,4,2,0,60,0,1 -127443,-100,4,2,0,80,0,1 -128263,-100,4,2,0,60,0,1 -128380,-100,4,2,0,80,0,1 -129201,-100,4,2,0,60,0,1 -129318,-100,4,2,0,80,0,1 -129670,-200,4,2,0,40,0,0 -144670,-133.333333333333,4,2,0,40,0,0 -159670,-133.333333333333,4,2,0,40,0,0 -163420,-133.333333333333,4,2,0,45,0,0 -163888,-125,4,2,0,50,0,0 -164357,-117.647058823529,4,2,0,55,0,0 -164826,-111.111111111111,4,2,0,60,0,0 -165295,-105.263157894737,4,2,0,65,0,0 -165763,-100,4,2,0,70,0,0 -166232,-100,4,2,0,40,0,0 -167170,-100,4,2,0,80,0,1 -167638,-100,4,2,0,60,0,1 -167755,-100,4,2,0,80,0,1 -168576,-100,4,2,0,60,0,1 -168693,-100,4,2,0,80,0,1 -169513,-100,4,2,0,60,0,1 -169630,-100,4,2,0,80,0,1 -170451,-100,4,2,0,60,0,1 -170568,-100,4,2,0,80,0,1 -171388,-100,4,2,0,60,0,1 -171505,-100,4,2,0,80,0,1 -172326,-100,4,2,0,60,0,1 -172443,-100,4,2,0,80,0,1 -173263,-100,4,2,0,60,0,1 -173380,-100,4,2,0,80,0,1 -174201,-100,4,2,0,60,0,1 -174318,-100,4,2,0,80,0,1 -175138,-100,4,2,0,60,0,1 -175255,-100,4,2,0,80,0,1 -176076,-100,4,2,0,60,0,1 -176193,-100,4,2,0,80,0,1 -177013,-100,4,2,0,60,0,1 -177130,-100,4,2,0,80,0,1 -177951,-100,4,2,0,60,0,1 -178068,-100,4,2,0,80,0,1 -178888,-100,4,2,0,60,0,1 -179005,-100,4,2,0,80,0,1 -179826,-100,4,2,0,60,0,1 -179943,-100,4,2,0,80,0,1 -180763,-100,4,2,0,60,0,1 -180880,-100,4,2,0,80,0,1 -180998,-100,4,2,0,80,0,0 -181466,-100,4,2,0,60,0,0 -181584,-100,4,2,0,80,0,0 -181935,-100,4,2,0,80,0,0 -182170,-100,4,2,0,80,0,1 -182638,-100,4,2,0,60,0,1 -182755,-100,4,2,0,80,0,1 -183576,-100,4,2,0,60,0,1 -183693,-100,4,2,0,80,0,1 -184513,-100,4,2,0,60,0,1 -184630,-100,4,2,0,80,0,1 -185451,-100,4,2,0,60,0,1 -185568,-100,4,2,0,80,0,1 -186388,-100,4,2,0,60,0,1 -186505,-100,4,2,0,80,0,1 -187326,-100,4,2,0,60,0,1 -187443,-100,4,2,0,80,0,1 -188263,-100,4,2,0,60,0,1 -188380,-100,4,2,0,80,0,1 -189201,-100,4,2,0,60,0,1 -189318,-100,4,2,0,80,0,1 -190138,-100,4,2,0,60,0,1 -190255,-100,4,2,0,80,0,1 -191076,-100,4,2,0,60,0,1 -191193,-100,4,2,0,80,0,1 -192013,-100,4,2,0,60,0,1 -192130,-100,4,2,0,80,0,1 -192951,-100,4,2,0,60,0,1 -193068,-100,4,2,0,80,0,1 -193888,-100,4,2,0,60,0,1 -194005,-100,4,2,0,80,0,1 -194826,-100,4,2,0,60,0,1 -194943,-100,4,2,0,80,0,1 -195295,-100,4,2,0,50,0,1 -195529,-100,4,2,0,52,0,1 -195646,-100,4,2,0,54,0,1 -195763,-100,4,2,0,56,0,1 -195880,-100,4,2,0,58,0,1 -195998,-100,4,2,0,60,0,1 -196115,-100,4,2,0,62,0,1 -196232,-100,4,2,0,64,0,1 -196349,-100,4,2,0,68,0,1 -196466,-100,4,2,0,70,0,1 -196584,-100,4,2,0,72,0,1 -196701,-100,4,2,0,74,0,1 -196818,-100,4,2,0,76,0,1 -196935,-100,4,2,0,78,0,1 -197052,-100,4,2,0,80,0,1 -197170,-100,4,2,0,80,0,0 -197873,-100,4,2,0,60,0,0 -197990,-100,4,2,0,80,0,0 -198341,-100,4,2,0,60,0,0 -199045,-100,4,2,0,80,0,0 -199279,-100,4,2,0,60,0,0 -199630,-100,4,2,0,80,0,0 -200216,-100,4,2,0,60,0,0 -200334,-100,4,2,0,80,0,0 -201623,-100,4,2,0,60,0,0 -201740,-100,4,2,0,80,0,0 -202326,-100,4,2,0,60,0,0 -202443,-100,4,2,0,80,0,0 -203029,-100,4,2,0,60,0,0 -203498,-100,4,2,0,80,0,0 -203966,-100,4,2,0,60,0,0 -204201,-100,4,2,0,80,0,0 -205373,-100,4,2,0,60,0,0 -205490,-100,4,2,0,80,0,0 -205841,-100,4,2,0,60,0,0 -206076,-100,4,2,0,60,0,0 -206545,-100,4,2,0,80,0,0 -206779,-100,4,2,0,60,0,0 -207130,-100,4,2,0,80,0,0 -207716,-100,4,2,0,60,0,0 -207951,-100,4,2,0,80,0,0 -209123,-100,4,2,0,60,0,0 -209240,-100,4,2,0,80,0,0 -209826,-100,4,2,0,60,0,0 -209943,-100,4,2,0,80,0,0 -210529,-100,4,2,0,60,0,0 -210880,-100,4,2,0,80,0,0 -211232,-100,4,2,0,60,0,0 -211701,-100,4,2,0,70,0,0 -212170,-100,4,2,0,80,0,0 -212873,-100,4,2,0,60,0,0 -212990,-100,4,2,0,80,0,0 -213341,-100,4,2,0,60,0,0 -213576,-100,4,2,0,60,0,0 -214045,-100,4,2,0,80,0,0 -214279,-100,4,2,0,60,0,0 -214630,-100,4,2,0,80,0,0 -215216,-100,4,2,0,60,0,0 -215451,-100,4,2,0,80,0,0 -216623,-100,4,2,0,60,0,0 -216740,-100,4,2,0,80,0,0 -217326,-100,4,2,0,60,0,0 -217443,-100,4,2,0,80,0,0 -218029,-100,4,2,0,60,0,0 -218498,-100,4,2,0,80,0,0 -218732,-100,4,2,0,50,0,0 -219670,-100,4,2,0,70,0,0 -220138,-100,4,2,0,65,0,0 -220373,-100,4,2,0,45,0,0 -220490,-100,4,2,0,65,0,0 -220607,-100,4,2,0,60,0,0 -220841,-100,4,2,0,35,0,0 -221076,-100,4,2,0,35,0,0 -221545,-100,4,2,0,50,0,0 -221779,-100,4,2,0,30,0,0 -222013,-111.111111111111,4,2,0,25,0,0 -222130,-111.111111111111,4,2,0,40,0,0 -222482,-125,4,2,0,40,0,0 -222716,-125,4,2,0,20,0,0 -222951,-100,4,2,0,15,0,0 -223420,-100,4,2,0,30,0,0 -224357,-100,4,2,0,25,0,0 -225295,-100,4,2,0,20,0,0 -226232,-100,4,2,0,15,0,0 -226701,-100,4,2,0,10,0,0 -227170,-100,4,2,0,5,0,0 - - -[Colours] - Combo1 : 17,254,176 -Combo2 : 173,255,95 -Combo3 : 255,88,100 -Combo4 : 255,94,55 - -[HitObjects] -320,256,2170,6,0,P|256:284|192:256,1,144,4|0,0:0|0:0,0:0:0:0: -144,184,2873,1,0,0:0:0:0: -108,260,3107,2,0,P|112:296|100:336,1,72 -28,288,3576,2,0,P|24:252|36:212,1,72,0|0,0:0|0:0,0:0:0:0: -76,140,4045,6,0,L|220:136,1,144,4|0,0:0|0:0,0:0:0:0: -292,88,4748,1,0,0:0:0:0: -292,88,4982,2,0,P|304:120|300:168,1,72 -388,168,5451,2,0,P|396:133|416:103,1,72,0|0,0:0|0:0,0:0:0:0: -472,172,5920,6,0,B|470:200|457:222|457:222|488:256|476:308,1,144,4|0,0:0|0:0,0:0:0:0: -396,280,6623,1,0,0:0:0:0: -324,328,6857,2,0,P|288:332|252:324,1,72 -180,280,7326,2,0,L|108:284,1,72,0|0,0:0|0:0,0:0:0:0: -256,192,7795,12,0,9670,0:0:0:0: -428,212,10138,1,0,0:0:0:0: -292,320,10607,1,0,0:0:0:0: -184,184,11076,2,0,L|112:180,1,72,0|0,0:0|0:0,0:0:0:0: -24,172,11545,5,6,0:0:0:0: -160,280,12013,1,0,0:0:0:0: -268,144,12482,1,0,0:0:0:0: -132,36,12951,2,0,L|204:32,1,72,0|0,0:0|0:0,0:0:0:0: -284,60,13420,6,0,P|340:100|344:180,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0: -268,144,14591,1,0,0:0:0:0: -284,228,14826,2,0,P|316:248|364:252,1,72,0|0,0:0|0:0,0:0:0:0: -436,248,15295,6,0,P|372:272|344:340,1,144,6|2,0:0|0:0,0:0:0:0: -168,338,16232,2,0,P|141:273|76:248,1,144,2|2,0:0|0:0,0:0:0:0: -4,296,16935,1,0,0:0:0:0: -80,336,17170,5,6,0:0:0:0: -44,168,17638,1,0,0:0:0:0: -212,128,18107,1,0,0:0:0:0: -248,296,18576,2,0,P|284:288|320:292,1,72,0|0,0:0|0:0,0:0:0:0: -400,324,19045,5,6,0:0:0:0: -280,200,19513,1,0,0:0:0:0: -368,52,19982,1,0,0:0:0:0: -488,176,20451,2,0,P|452:168|416:172,1,72,0|0,0:0|0:0,0:0:0:0: -336,200,20920,6,0,P|284:216|200:192,1,144,6|0,0:0|0:0,0:0:0:0: -200,192,21857,2,0,L|204:264,1,72,0|0,0:3|0:0,0:0:0:0: -117,244,22326,2,0,L|120:172,1,72,0|0,0:0|0:0,0:0:0:0: -40,152,22795,6,0,L|28:296,2,144,6|0|0,0:0|0:0|0:0,0:0:0:0: -152,24,24201,1,0,0:0:0:0: -220,76,24435,1,0,3:0:0:0: -304,56,24670,6,0,P|288:120|296:196,1,144,4|2,0:3|0:3,0:0:0:0: -344,268,25373,1,0,0:0:0:0: -416,316,25607,2,0,P|452:312|508:316,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -244,344,26545,6,0,P|176:356|108:328,1,144,4|2,0:3|0:3,0:0:0:0: -60,256,27248,1,0,0:0:0:0: -36,172,27482,2,0,L|40:100,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -188,252,28420,6,0,P|192:184|196:100,1,144,4|2,0:3|0:3,0:0:0:0: -140,40,29123,1,0,0:0:0:0: -140,40,29357,2,0,B|172:16|220:24|220:24|288:36,1,144,0|2,0:0|0:3,0:0:0:0: -364,52,30060,1,0,0:0:0:0: -308,116,30295,6,0,B|300:168|300:168|328:256,1,144,4|2,0:3|0:3,0:0:0:0: -340,340,30998,1,0,0:0:0:0: -260,308,31232,2,0,L|188:304,1,72,0|2,0:0|0:3,0:0:0:0: -100,296,31701,1,2,0:3:0:0: -136,374,31935,1,0,0:0:0:0: -152,224,32170,6,0,P|160:152|132:88,1,144,4|2,0:3|0:3,0:0:0:0: -56,48,32873,1,0,0:0:0:0: -60,136,33107,2,0,L|56:208,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -224,76,34045,6,0,P|289:104|360:96,1,144,4|2,0:3|0:3,0:0:0:0: -432,48,34748,1,0,0:0:0:0: -440,132,34982,2,0,B|432:156|432:156|436:204,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -448,304,35920,6,0,B|412:315|380:292|380:292|348:269|312:280,1,144,4|2,0:3|0:3,0:0:0:0: -332,364,36623,1,0,0:0:0:0: -247,339,36857,2,0,P|230:308|225:273,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -312,280,37560,6,0,L|316:172,1,108 -134,35,38966,5,0,0:0:0:0: -72,96,39201,2,0,P|119:119|171:111,1,108,0|0,0:0|0:0,0:0:0:0: -192,100,39670,6,0,L|200:172,1,72,4|2,0:0|0:0,0:0:0:0: -147,240,40138,2,0,P|133:272|132:308,1,72,0|2,1:0|0:0,0:0:0:0: -216,292,40607,2,0,B|260:308|260:308|356:292,1,144,4|0,2:3|1:0,1:0:0:0: -356,292,41310,1,2,0:0:0:0: -436,327,41545,6,0,P|441:292|435:257,1,72,4|2,0:3|0:0,0:0:0:0: -364,204,42013,2,0,P|336:144|352:68,1,144,0|4,1:0|2:3,1:0:0:0: -404,0,42716,1,2,0:0:0:0: -440,80,42951,2,0,B|464:84|464:84|512:80,1,72,0|2,1:0|0:0,0:0:0:0: -351,71,43420,6,0,B|296:68|296:68|268:76|268:76|196:72,1,144,4|0,2:3|1:0,1:0:0:0: -120,68,44123,1,2,0:0:0:0: -160,144,44357,2,0,P|172:180|168:232,1,72,4|2,0:3|0:0,0:0:0:0: -76,264,44826,2,0,P|76:228|88:194,1,72,0|2,1:0|0:0,0:0:0:0: -160,144,45295,5,4,0:3:0:0: -244,164,45529,1,2,0:0:0:0: -268,248,45763,2,0,L|344:252,1,72,0|2,1:0|0:0,0:0:0:0: -408,156,46232,2,0,L|336:159,1,72,4|2,0:3|0:0,0:0:0:0: -212,72,46701,2,0,L|288:76,1,72,0|2,1:0|0:0,0:0:0:0: -400,72,47170,6,0,P|464:96|488:172,1,144,4|0,2:0|1:0,1:0:0:0: -476,248,47873,1,2,0:0:0:0: -436,324,48107,2,0,L|284:320,1,144,4|0,2:3|1:0,1:0:0:0: -204,316,48810,1,2,0:0:0:0: -127,355,49045,6,0,P|120:321|124:285,1,72,4|2,0:3|0:0,0:0:0:0: -192,232,49513,2,0,L|335:228,1,144,0|4,1:0|2:3,1:0:0:0: -412,188,50216,1,2,0:0:0:0: -444,108,50451,2,0,P|452:72|448:36,1,72,0|2,1:0|0:0,0:0:0:0: -368,68,50920,6,0,B|332:79|300:56|300:56|268:33|232:44,1,144,4|0,2:3|1:0,1:0:0:0: -152,76,51623,1,2,0:0:0:0: -76,116,51857,2,0,L|80:268,1,144,4|0,2:3|1:0,1:0:0:0: -80,260,52560,1,2,0:0:0:0: -8,308,52795,6,0,P|34:334|69:346,1,72,4|2,0:3|0:0,0:0:0:0: -148,312,53263,2,0,P|163:278|162:241,1,72,0|2,1:0|0:0,0:0:0:0: -156,156,53732,5,0,3:0:0:0: -156,156,53966,1,2,0:0:0:0: -236,196,54201,2,0,L|312:192,1,72,8|0,0:3|0:0,0:0:0:0: -368,256,54670,6,0,P|392:216|352:116,1,144,4|2,0:0|1:2,0:0:0:0: -288,92,55373,1,0,0:0:0:0: -360,40,55607,2,0,L|432:36,1,72,4|0,0:3|3:0,0:0:0:0: -288,92,56076,2,0,L|216:88,1,72,2|0,1:2|0:0,0:0:0:0: -132,72,56545,6,0,P|172:88|200:184,1,144,4|2,0:3|1:2,0:0:0:0: -143,241,57248,1,0,0:0:0:0: -65,202,57482,2,0,P|87:174|119:157,1,72,4|0,0:3|3:0,0:0:0:0: -132,324,57951,2,0,P|98:312|72:288,1,72,2|0,1:2|0:0,0:0:0:0: -143,241,58420,6,0,L|288:240,1,144,4|2,0:3|1:2,0:0:0:0: -372,240,59123,1,0,0:0:0:0: -330,314,59357,2,0,P|318:350|322:390,1,72,4|0,0:3|3:0,0:0:0:0: -452,264,59826,2,0,P|453:228|442:194,1,72,2|0,1:2|0:0,0:0:0:0: -384,128,60295,6,0,B|336:144|336:144|244:128,1,144,4|2,0:3|1:2,0:0:0:0: -164,160,60998,2,0,P|160:116|168:88,1,72,0|4,0:0|0:3,0:0:0:0: -244,128,61466,2,0,P|248:172|240:200,1,72,0|2,3:0|1:2,0:0:0:0: -168,248,61935,1,0,0:0:0:0: -120,320,62170,6,0,P|196:328|252:272,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: -80,244,63341,1,0,3:0:0:0: -100,160,63576,2,0,L|24:156,1,72,2|0,1:2|0:0,0:0:0:0: -180,128,64045,6,0,P|249:138|304:94,1,144,4|2,0:3|1:2,0:0:0:0: -226,57,64748,1,0,0:0:0:0: -304,94,64982,2,0,L|300:166,1,72,4|0,0:3|3:0,0:0:0:0: -377,203,65451,2,0,L|388:132,1,72,2|0,1:2|0:0,0:0:0:0: -468,180,65920,6,0,L|432:328,1,144,4|2,0:3|1:2,0:0:0:0: -276,252,66857,2,0,P|208:248|140:280,1,144,4|2,0:3|1:2,0:0:0:0: -84,344,67560,1,0,0:0:0:0: -56,260,67795,6,0,L|52:188,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -168,128,68732,2,0,L|172:56,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -244,168,69435,1,0,0:0:0:0: -332,164,69670,1,4,0:3:0:0: -208,328,84670,6,0,P|224:264|216:188,1,144,4|2,0:3|0:3,0:0:0:0: -168,116,85373,1,0,0:0:0:0: -96,68,85607,2,0,P|60:72|4:68,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -268,40,86545,6,0,P|336:28|404:56,1,144,4|2,0:3|0:3,0:0:0:0: -452,128,87248,1,0,0:0:0:0: -476,212,87482,2,0,L|472:284,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -324,132,88420,6,0,P|320:200|316:284,1,144,4|2,0:3|0:3,0:0:0:0: -372,344,89123,1,0,0:0:0:0: -372,344,89357,2,0,B|340:368|292:360|292:360|224:348,1,144,0|2,0:0|0:3,0:0:0:0: -148,332,90060,1,0,0:0:0:0: -204,268,90295,6,0,B|212:216|212:216|184:128,1,144,4|2,0:3|0:3,0:0:0:0: -172,44,90998,1,0,0:0:0:0: -252,76,91232,2,0,L|324:80,1,72,0|2,0:0|0:3,0:0:0:0: -412,88,91701,1,2,0:3:0:0: -377,9,91935,1,0,0:0:0:0: -360,160,92170,6,0,P|352:232|380:296,1,144,4|2,0:3|0:3,0:0:0:0: -456,336,92873,1,0,0:0:0:0: -452,248,93107,2,0,L|456:176,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -288,308,94045,6,0,P|223:280|152:288,1,144,4|2,0:3|0:3,0:0:0:0: -80,336,94748,1,0,0:0:0:0: -72,252,94982,2,0,B|80:228|80:228|76:180,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -64,80,95920,6,0,B|100:69|132:92|132:92|164:115|200:104,1,144,4|2,0:3|0:3,0:0:0:0: -180,20,96623,1,0,0:0:0:0: -265,45,96857,2,0,P|282:76|287:111,2,72,0|0|2,0:0|0:0|0:3,0:0:0:0: -200,104,97560,1,0,0:0:0:0: -200,104,97677,1,0,0:0:0:0: -200,104,97795,6,0,B|196:142|217:166|217:166|176:180|160:220,1,144,4|0,0:3|0:0,0:0:0:0: -240,248,98966,5,0,0:0:0:0: -202,325,99201,2,0,P|254:333|301:309,1,108,0|0,0:0|0:0,0:0:0:0: -315,292,99670,6,0,L|323:220,1,72,4|2,0:0|0:0,0:0:0:0: -365,144,100138,2,0,P|379:112|380:76,1,72,0|2,1:0|0:0,0:0:0:0: -296,92,100607,2,0,B|252:76|252:76|156:92,1,144,4|0,2:3|1:0,1:0:0:0: -156,92,101310,1,2,0:0:0:0: -76,57,101545,6,0,P|71:92|77:127,1,72,4|2,0:3|0:0,0:0:0:0: -148,180,102013,2,0,P|176:240|160:316,1,144,0|4,1:0|2:3,1:0:0:0: -108,384,102716,1,2,0:0:0:0: -72,304,102951,2,0,B|48:300|48:300|0:304,1,72,0|2,1:0|0:0,0:0:0:0: -161,313,103420,6,0,B|216:316|216:316|244:308|244:308|316:312,1,144,4|0,2:3|1:0,1:0:0:0: -392,316,104123,1,2,0:0:0:0: -352,240,104357,2,0,P|340:204|344:152,1,72,4|2,0:3|0:0,0:0:0:0: -436,120,104826,2,0,P|436:156|424:190,1,72,0|2,1:0|0:0,0:0:0:0: -352,240,105295,5,4,0:3:0:0: -268,220,105529,1,2,0:0:0:0: -244,136,105763,2,0,L|168:132,1,72,0|2,1:0|0:0,0:0:0:0: -104,228,106232,2,0,L|176:225,1,72,4|2,0:3|0:0,0:0:0:0: -300,312,106701,2,0,L|224:308,1,72,0|2,1:0|0:0,0:0:0:0: -112,312,107170,6,0,P|48:288|24:212,1,144,4|0,2:0|1:0,1:0:0:0: -36,136,107873,1,2,0:0:0:0: -76,60,108107,2,0,L|228:64,1,144,4|0,2:3|1:0,1:0:0:0: -308,68,108810,1,2,0:0:0:0: -385,29,109045,6,0,P|392:63|388:99,1,72,4|2,0:3|0:0,0:0:0:0: -320,152,109513,2,0,L|177:156,1,144,0|4,1:0|2:3,1:0:0:0: -100,196,110216,1,2,0:0:0:0: -68,276,110451,2,0,P|60:312|64:348,1,72,0|2,1:0|0:0,0:0:0:0: -144,316,110920,6,0,B|180:305|212:328|212:328|244:351|280:340,1,144,4|0,2:3|1:0,1:0:0:0: -360,308,111623,1,2,0:0:0:0: -436,268,111857,2,0,L|432:116,1,144,4|0,2:3|1:0,1:0:0:0: -432,124,112560,1,2,0:0:0:0: -504,76,112795,6,0,P|478:50|443:38,1,72,4|2,0:3|0:0,0:0:0:0: -364,72,113263,2,0,P|349:106|350:143,1,72,0|2,1:0|0:0,0:0:0:0: -356,228,113732,5,0,3:0:0:0: -356,228,113966,1,2,0:0:0:0: -276,188,114201,2,0,L|200:192,1,72,8|0,0:3|0:0,0:0:0:0: -144,128,114670,6,0,P|120:168|160:268,1,144,4|2,0:0|1:2,0:0:0:0: -224,292,115373,1,0,0:0:0:0: -152,344,115607,2,0,L|80:348,1,72,4|0,0:3|3:0,0:0:0:0: -224,292,116076,2,0,L|296:296,1,72,2|0,1:2|0:0,0:0:0:0: -380,312,116545,6,0,P|340:296|312:200,1,144,4|2,0:3|1:2,0:0:0:0: -369,143,117248,1,0,0:0:0:0: -447,182,117482,2,0,P|425:210|393:227,1,72,4|0,0:3|3:0,0:0:0:0: -380,60,117951,2,0,P|414:72|440:96,1,72,2|0,1:2|0:0,0:0:0:0: -369,143,118420,6,0,L|224:144,1,144,4|2,0:3|1:2,0:0:0:0: -140,144,119123,1,0,0:0:0:0: -182,70,119357,2,0,P|194:34|190:-6,1,72,4|0,0:3|3:0,0:0:0:0: -60,120,119826,2,0,P|59:156|70:190,1,72,2|0,1:2|0:0,0:0:0:0: -128,256,120295,6,0,B|176:240|176:240|268:256,1,144,4|2,0:3|1:2,0:0:0:0: -348,224,120998,2,0,P|352:268|344:296,1,72,0|4,0:0|0:3,0:0:0:0: -268,256,121466,2,0,P|264:212|272:184,1,72,0|2,3:0|1:2,0:0:0:0: -344,136,121935,1,0,0:0:0:0: -392,64,122170,6,0,P|316:56|260:112,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: -432,140,123341,1,0,3:0:0:0: -412,224,123576,2,0,L|488:228,1,72,2|0,1:2|0:0,0:0:0:0: -332,256,124045,6,0,P|263:246|208:290,1,144,4|2,0:3|1:2,0:0:0:0: -286,327,124748,1,0,0:0:0:0: -208,290,124982,2,0,L|212:218,1,72,4|0,0:3|3:0,0:0:0:0: -135,181,125451,2,0,L|124:252,1,72,2|0,1:2|0:0,0:0:0:0: -44,204,125920,6,0,L|80:56,1,144,4|2,0:3|1:2,0:0:0:0: -236,132,126857,2,0,P|304:136|372:104,1,144,4|2,0:3|1:2,0:0:0:0: -428,40,127560,1,0,0:0:0:0: -456,124,127795,6,0,L|460:196,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -344,256,128732,2,0,L|340:328,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -268,216,129435,1,0,0:0:0:0: -180,220,129670,5,4,2:0:0:0: -256,40,130373,1,2,0:0:0:0: -64,68,131076,1,2,0:0:0:0: -92,136,131310,1,0,0:0:0:0: -64,204,131545,6,0,L|60:288,1,72 -31,343,132248,2,0,P|86:345|127:309,1,108 -332,220,133420,5,2,0:0:0:0: -256,40,134123,1,2,0:0:0:0: -448,68,134826,1,2,0:0:0:0: -420,136,135060,1,0,0:0:0:0: -448,204,135295,6,0,L|452:288,1,72,2|0,0:0|0:0,0:0:0:0: -480,343,135998,2,0,P|426:345|385:309,1,108 -256,192,137170,5,2,0:0:0:0: -156,360,137873,1,2,0:0:0:0: -356,360,138576,2,0,L|352:308,1,36,2|0,0:0|0:0,0:0:0:0: -304,268,139045,6,0,P|336:253|372:252,1,72 -448,260,139748,2,0,L|444:152,1,108 -256,192,140920,5,2,0:0:0:0: -356,24,141623,1,2,0:0:0:0: -156,24,142326,2,0,L|160:72,1,36,2|0,0:0|0:0,0:0:0:0: -208,116,142795,6,0,P|176:131|140:132,1,72,2|0,0:0|0:0,0:0:0:0: -64,124,143498,2,0,L|68:232,1,108 -68,232,144670,5,4,0:3:0:0: -216,320,145138,1,4,0:3:0:0: -304,172,145607,1,4,0:3:0:0: -156,84,146075,1,4,0:3:0:0: -296,320,146545,5,4,0:3:0:0: -208,172,147013,1,4,0:3:0:0: -356,84,147482,1,4,0:3:0:0: -444,232,147950,1,4,0:3:0:0: -296,320,148420,6,0,P|252:328|192:296,2,108.000004119873,4|4|4,0:3|0:3|0:3,0:0:0:0: -260,248,149591,1,0,0:0:0:0: -320,196,149826,2,0,L|316:140,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0: -120,236,159670,6,0,L|176:232,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0: -160,152,160138,2,0,L|104:156,1,54.0000020599366,2|0,0:0|0:0,0:0:0:0: -240,180,160607,2,0,P|292:188|344:172,1,108.000004119873,4|2,0:3|0:0,3:0:0:0: -408,120,161310,1,0,3:0:0:0: -424,200,161545,6,0,L|420:256,1,54.0000020599366,4|0,0:3|0:0,0:0:0:0: -376,320,162013,2,0,P|396:328|480:304,2,108.000004119873,2|6|2,2:0|0:3|2:0,3:0:0:0: -312,268,163185,1,0,0:0:0:0: -296,348,163420,6,0,L|240:344,1,54.0000020599366,4|0,3:0|3:0,0:0:0:0: -160,320,163888,2,0,L|100:316,1,57.6,4|0,3:0|3:0,0:0:0:0: -64,232,164357,6,0,L|128:228,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0: -204,200,164825,2,0,L|268:196,1,61.2000011672974,4|0,3:0|3:0,0:0:0:0: -232,108,165295,6,0,L|164:104,1,68.399998173523,4|0,3:0|3:0,0:0:0:0: -80,84,165763,2,0,L|4:80,1,72,4|0,3:0|3:0,0:0:0:0: -324,120,167170,6,0,P|388:128|456:92,1,144,4|2,0:0|1:2,0:0:0:0: -496,168,167873,1,0,0:0:0:0: -496,168,168107,2,0,P|484:204|488:256,1,72,4|0,0:3|3:0,0:0:0:0: -408,296,168576,2,0,P|398:261|378:231,1,72,2|0,1:2|0:0,0:0:0:0: -296,200,169045,6,0,B|228:228|156:204,1,144,4|2,0:3|1:2,0:0:0:0: -84,156,169748,1,0,0:0:0:0: -80,244,169982,2,0,L|76:316,1,72,4|0,0:3|3:0,0:0:0:0: -170,274,170451,2,0,L|156:204,1,72,2|0,1:2|0:0,0:0:0:0: -216,140,170920,6,0,L|284:276,1,144,4|2,0:3|1:2,0:0:0:0: -320,344,171623,1,0,0:0:0:0: -372,276,171857,2,0,P|366:240|349:207,1,72,4|0,0:3|3:0,0:0:0:0: -312,132,172326,2,0,L|276:60,1,72,2|0,1:2|0:0,0:0:0:0: -208,20,172795,6,0,P|272:36|348:12,1,144,4|2,0:3|1:2,0:0:0:0: -424,48,173498,2,0,L|412:132,1,72,0|4,0:0|0:3,0:0:0:0: -484,168,173966,2,0,L|472:252,1,72,0|2,3:0|1:2,0:0:0:0: -400,280,174435,1,0,0:0:0:0: -346,348,174670,6,0,P|414:363|472:324,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: -312,268,175841,1,0,3:0:0:0: -256,336,176076,2,0,L|184:332,1,72,2|0,1:2|0:0,0:0:0:0: -80,244,176545,6,0,B|140:248|140:248|164:244|164:244|223:247,1,144,4|2,0:3|1:2,0:0:0:0: -312,268,177248,1,0,0:0:0:0: -224,247,177482,2,0,P|240:215|272:187,1,72,4|0,0:3|3:0,0:0:0:0: -204,131,177951,2,0,P|233:111|275:103,1,72,2|0,1:2|0:0,0:0:0:0: -240,23,178420,6,0,B|280:15|316:35|316:35|376:71,1,144,4|2,0:3|1:2,0:0:0:0: -399,236,179357,2,0,B|359:244|323:224|323:224|263:188,1,144,4|2,0:3|1:2,0:0:0:0: -204,132,180060,1,0,0:0:0:0: -184,216,180295,6,0,L|188:288,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -120,156,180998,1,0,0:0:0:0: -56,96,181232,2,0,L|60:24,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: -36,180,181935,1,0,0:0:0:0: -100,240,182170,6,0,P|144:300|116:380,2,144,4|2|4,0:0|1:2|0:3,0:0:0:0: -60,316,183341,1,0,0:0:0:0: -220,352,183576,2,0,L|308:348,1,72,2|0,1:2|0:0,0:0:0:0: -396,264,184045,6,0,B|336:268|336:268|312:264|312:264|253:267,1,144,4|2,0:3|1:2,0:0:0:0: -253,267,184748,1,0,0:0:0:0: -268,180,184982,2,0,L|339:177,1,72,4|0,0:3|0:0,0:0:0:0: -164,280,185451,2,0,L|92:282,1,72,2|0,1:2|0:0,0:0:0:0: -52,208,185920,6,0,P|8:268|32:344,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: -140,212,187091,1,0,0:0:0:0: -92,284,187326,2,0,P|104:316|100:368,1,72,2|0,1:2|0:0,0:0:0:0: -52,208,187795,6,0,P|48:136|76:72,1,144,4|2,0:3|1:2,0:0:0:0: -160,52,188498,2,0,P|188:28|220:16,1,72,0|4,0:0|0:3,0:0:0:0: -232,100,188966,2,0,P|268:93|301:98,1,72,0|2,0:0|1:2,0:0:0:0: -372,152,189435,1,0,0:0:0:0: -420,224,189670,6,0,P|428:296|400:360,2,144,4|2|4,0:3|1:2|0:3,0:0:0:0: -372,152,190841,1,0,0:0:0:0: -392,68,191076,2,0,L|465:64,1,72,2|0,1:2|0:0,0:0:0:0: -304,92,191545,6,0,P|236:104|168:76,1,144,4|2,0:3|1:2,0:0:0:0: -108,12,192248,1,0,0:0:0:0: -168,76,192482,2,0,L|172:152,1,72,4|0,0:3|0:0,0:0:0:0: -80,136,192951,2,0,L|101:204,1,72,2|0,1:2|0:0,0:0:0:0: -12,220,193420,6,0,B|50:279|50:279|80:300|120:292,1,144,4|2,0:3|1:2,0:0:0:0: -284,232,194357,2,0,B|320:221|352:244|352:244|384:267|420:256,1,144,4|2,0:3|1:2,0:0:0:0: -488,200,195060,1,0,0:0:0:0: -507,284,195295,6,0,P|492:315|464:338,1,72,4|0,0:0|0:0,0:0:0:0: -380,356,195763,2,0,L|236:352,1,144,0|4,1:0|0:3,0:0:0:0: -152,328,196466,1,0,3:0:0:0: -64,336,196701,2,0,P|29:325|4:300,1,72,0|0,1:0|0:0,0:0:0:0: -76,252,197170,6,0,P|108:188|96:116,1,144,4|0,0:0|1:0,0:0:0:0: -36,56,197873,1,2,0:0:0:0: -120,32,198107,2,0,L|192:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -248,152,199045,6,0,P|280:168|304:196,1,72,4|2,0:3|0:0,0:0:0:0: -336,277,199513,2,0,P|306:296|269:303,1,72,2|0,1:2|0:0,0:0:0:0: -183,290,199982,2,0,P|180:254|193:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: -436,252,200920,6,0,P|404:188|416:116,1,144,4|0,0:3|1:0,0:0:0:0: -476,56,201623,1,2,0:0:0:0: -392,32,201857,2,0,L|320:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0: -264,152,202795,6,0,P|232:168|208:196,1,72,4|2,0:3|0:0,0:0:0:0: -176,277,203263,2,0,P|205:296|242:303,1,72,2|0,1:2|0:0,0:0:0:0: -329,290,203732,2,0,P|331:254|318:219,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: -72,324,204670,6,0,B|60:272|60:272|76:180,1,144,4|0,0:0|1:0,0:0:0:0: -92,96,205373,1,2,0:0:0:0: -8,124,205607,2,0,P|5:88|14:53,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -168,192,206545,6,0,P|200:174|237:173,1,72,4|2,0:3|0:0,0:0:0:0: -320,160,207013,2,0,P|318:196|301:229,1,72,2|0,1:2|0:0,0:0:0:0: -272,307,207482,2,0,P|240:287|221:256,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: -440,324,208420,6,0,B|452:272|452:272|436:180,1,144,4|0,0:3|1:0,0:0:0:0: -420,96,209123,1,2,0:0:0:0: -504,124,209357,2,0,P|507:88|498:53,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0: -344,192,210295,6,0,P|311:174|274:173,1,72,4|2,0:3|0:0,0:0:0:0: -190,156,210763,2,0,P|191:192|208:225,1,72,2|0,1:2|0:0,0:0:0:0: -288,256,211232,1,4,0:3:0:0: -132,332,211701,1,0,1:0:0:0: -28,192,212170,6,0,P|16:120|44:56,1,144,4|0,0:0|1:0,0:0:0:0: -120,16,212873,1,2,0:0:0:0: -204,32,213107,2,0,L|304:28,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -192,204,214045,6,0,P|196:240|216:272,1,72,4|2,0:3|0:0,0:0:0:0: -298,241,214513,2,0,P|327:219|345:186,1,72,6|0,1:2|0:0,0:0:0:0: -280,132,214982,2,0,P|246:117|209:118,2,72,4|2|0,0:3|0:0|1:0,0:0:0:0: -484,192,215920,6,0,P|496:120|468:56,1,144,4|0,0:3|1:0,0:0:0:0: -392,16,216623,1,2,0:0:0:0: -308,32,216857,2,0,L|208:28,2,72,4|0|2,0:3|0:0|1:2,0:0:0:0: -320,204,217795,6,0,P|316:240|296:272,1,72,4|2,0:3|0:0,0:0:0:0: -213,241,218263,2,0,P|184:219|166:186,1,72,2|0,1:2|0:0,0:0:0:0: -232,132,218732,2,0,B|260:112|300:116|300:116|384:128,1,144,4|0,0:3|1:0,0:0:0:0: -348,336,219670,6,0,B|320:356|280:352|280:352|196:340,1,144,4|0,0:0|1:0,0:0:0:0: -124,328,220373,1,2,0:0:0:0: -54,276,220607,2,0,P|41:308|39:345,2,72,4|2|2,0:3|0:0|1:2,0:0:0:0: -156,80,221545,6,0,L|251:94,1,72,4|2,0:3|0:0,0:0:0:0: -212,169,222013,2,0,L|148:160,1,64.799998022461,2|0,1:2|0:0,0:0:0:0: -140,240,222482,2,0,L|216:252,2,57.6,4|2|0,0:3|0:0|1:0,0:0:0:0: -256,192,223420,12,0,227170,0:0:0:0: -"; } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1d3baa6c0d..3d89c859c4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -896,6 +896,7 @@ + From b91524dbba0bdbfc1436dd1d1a140e296f518137 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 18:32:58 +0900 Subject: [PATCH 49/58] Give TestWorkingBeatmap's track a valid length --- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index 68bb3f6dd9..02a5c8a5fc 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -1,10 +1,12 @@ // 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.Audio.Track; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Tests.Beatmaps { @@ -24,6 +26,21 @@ namespace osu.Game.Tests.Beatmaps private readonly Beatmap beatmap; protected override Beatmap GetBeatmap() => beatmap; protected override Texture GetBackground() => null; - protected override Track GetTrack() => new TrackVirtual(); + + protected override Track GetTrack() + { + var lastObject = beatmap.HitObjects.LastOrDefault(); + if (lastObject != null) + return new TestTrack(((lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime) + 1000); + return new TrackVirtual(); + } + + private class TestTrack : TrackVirtual + { + public TestTrack(double length) + { + Length = length; + } + } } } From 13c20438ef93cd225005dcc47eef687b5556915e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 19:41:51 +0900 Subject: [PATCH 50/58] Fix build issues --- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index a29ee03975..3b43459428 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Beatmaps using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) using (var reader = new StreamReader(stream)) - return testBeatmapCache = Decoder.GetDecoder(reader).DecodeBeatmap(reader); + return testBeatmapCache = Decoder.GetDecoder(reader).Decode(reader); } private const string test_beatmap_data = From d2859d779d1de3b51cbb35edec81b98e2dea492e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Mar 2018 19:38:23 +0900 Subject: [PATCH 51/58] Create a base TestCaseEditor for rulests to derive --- osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs | 16 ++++++ .../osu.Game.Rulesets.Osu.csproj | 1 + osu.Game.Tests/Visual/TestCaseEditor.cs | 49 ------------------- osu.Game.Tests/osu.Game.Tests.csproj | 1 - osu.Game/Tests/Visual/TestCaseEditor.cs | 33 +++++++++++++ osu.Game/osu.Game.csproj | 1 + 6 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs delete mode 100644 osu.Game.Tests/Visual/TestCaseEditor.cs create mode 100644 osu.Game/Tests/Visual/TestCaseEditor.cs diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs new file mode 100644 index 0000000000..501992def3 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs @@ -0,0 +1,16 @@ +// 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 TestCaseEditor : Game.Tests.Visual.TestCaseEditor + { + public TestCaseEditor() + : base(new OsuRuleset()) + { + } + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 92cac71ad3..b4c5654de4 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -130,6 +130,7 @@ + diff --git a/osu.Game.Tests/Visual/TestCaseEditor.cs b/osu.Game.Tests/Visual/TestCaseEditor.cs deleted file mode 100644 index c626ca8e7f..0000000000 --- a/osu.Game.Tests/Visual/TestCaseEditor.cs +++ /dev/null @@ -1,49 +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 NUnit.Framework; -using osu.Framework.Allocation; -using osu.Game.Beatmaps; -using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Screens; - -namespace osu.Game.Tests.Visual -{ - [TestFixture] - public class TestCaseEditor : OsuTestCase - { - public override IReadOnlyList RequiredTypes => new[] { typeof(Editor), typeof(EditorScreen) }; - - private readonly Random rng; - - private BeatmapManager beatmaps; - private OsuGameBase osuGame; - - public TestCaseEditor() - { - rng = new Random(1337); - - Add(new Editor()); - AddStep("Next beatmap", nextBeatmap); - } - - [BackgroundDependencyLoader] - private void load(OsuGameBase osuGame, BeatmapManager beatmaps) - { - this.osuGame = osuGame; - this.beatmaps = beatmaps; - } - - private void nextBeatmap() - { - var sets = beatmaps.GetAllUsableBeatmapSets(); - if (sets.Count == 0) - return; - - BeatmapInfo info = sets[rng.Next(0, sets.Count)].Beatmaps[0]; - osuGame.Beatmap.Value = beatmaps.GetWorkingBeatmap(info); - } - } -} diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 1cfa7bc111..ed9580211b 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -126,7 +126,6 @@ - diff --git a/osu.Game/Tests/Visual/TestCaseEditor.cs b/osu.Game/Tests/Visual/TestCaseEditor.cs new file mode 100644 index 0000000000..76eae7acea --- /dev/null +++ b/osu.Game/Tests/Visual/TestCaseEditor.cs @@ -0,0 +1,33 @@ +// 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.Allocation; +using osu.Game.Rulesets; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Screens; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Tests.Visual +{ + public abstract class TestCaseEditor : OsuTestCase + { + public override IReadOnlyList RequiredTypes => new[] { typeof(Editor), typeof(EditorScreen) }; + + private readonly Ruleset ruleset; + + protected TestCaseEditor(Ruleset ruleset) + { + this.ruleset = ruleset; + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase osuGame) + { + osuGame.Beatmap.Value = new TestWorkingBeatmap(ruleset.RulesetInfo); + + Child = new Editor(); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3d89c859c4..c99ccd6945 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -902,6 +902,7 @@ + From 3354849cc9c05eb47d58abf570935f1fbf36865a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Mar 2018 22:01:18 +0900 Subject: [PATCH 52/58] Fix code formatting regression --- osu.Game/Skinning/LegacySkin.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 2caeed8480..5525cc483e 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -58,9 +58,14 @@ namespace osu.Game.Skinning private readonly SkinInfo skin; private readonly IResourceStore underlyingStore; - private string getPathForFile(string filename) => - skin.Files.FirstOrDefault(f => string.Equals(Path.GetFileNameWithoutExtension(f.Filename), filename.Split('/').Last(), StringComparison.InvariantCultureIgnoreCase))?.FileInfo - .StoragePath; + private string getPathForFile(string filename) + { + string lastPiece = filename.Split('/').Last(); + + var file = skin.Files.FirstOrDefault(f => + string.Equals(Path.GetFileNameWithoutExtension(f.Filename), lastPiece, StringComparison.InvariantCultureIgnoreCase)); + return file?.FileInfo.StoragePath; + } public LegacySkinResourceStore(SkinInfo skin, IResourceStore underlyingStore) { From 706c26c32b1f4a1912b119b7804a6f6a57b32c64 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Mar 2018 09:27:28 +0900 Subject: [PATCH 53/58] Remove extra whitespace --- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index 3b43459428..6d80ebffd4 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -341,9 +341,8 @@ SliderTickRate:2 226701,-100,4,2,0,10,0,0 227170,-100,4,2,0,5,0,0 - [Colours] - Combo1 : 17,254,176 +Combo1 : 17,254,176 Combo2 : 173,255,95 Combo3 : 255,88,100 Combo4 : 255,94,55 From 6ecd2afd2420cea1b11e7b704eb13a4ba68ed9d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Mar 2018 12:59:41 +0900 Subject: [PATCH 54/58] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 59004b46f2..d29c8365ba 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 59004b46f2c96ac02fec712e66f9f96fe252f2fa +Subproject commit d29c8365ba3cf7924b57cf22341f4af55658764c From e32eec9259ae7d463070e1e8da06402b50afa173 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Mar 2018 15:22:46 +0900 Subject: [PATCH 55/58] No more caching --- osu.Game/Tests/Beatmaps/TestBeatmap.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/TestBeatmap.cs b/osu.Game/Tests/Beatmaps/TestBeatmap.cs index 6d80ebffd4..7dc6079959 100644 --- a/osu.Game/Tests/Beatmaps/TestBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestBeatmap.cs @@ -17,15 +17,11 @@ namespace osu.Game.Tests.Beatmaps BeatmapInfo.Ruleset = ruleset; } - private static Beatmap testBeatmapCache; private static Beatmap createTestBeatmap() { - if (testBeatmapCache != null) - return testBeatmapCache; - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(test_beatmap_data))) using (var reader = new StreamReader(stream)) - return testBeatmapCache = Decoder.GetDecoder(reader).Decode(reader); + return Decoder.GetDecoder(reader).Decode(reader); } private const string test_beatmap_data = From 0c705b0397d192b4ee7ca2e6242dc26c9db4fae5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Mar 2018 15:57:05 +0900 Subject: [PATCH 56/58] Rename to EditorTestCase --- osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs | 3 ++- .../Tests/Visual/{TestCaseEditor.cs => EditorTestCase.cs} | 4 ++-- osu.Game/osu.Game.csproj | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) rename osu.Game/Tests/Visual/{TestCaseEditor.cs => EditorTestCase.cs} (85%) diff --git a/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs b/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs index 501992def3..a11f32935e 100644 --- a/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs +++ b/osu.Game.Rulesets.Osu/Tests/TestCaseEditor.cs @@ -2,11 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using NUnit.Framework; +using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestCaseEditor : Game.Tests.Visual.TestCaseEditor + public class TestCaseEditor : EditorTestCase { public TestCaseEditor() : base(new OsuRuleset()) diff --git a/osu.Game/Tests/Visual/TestCaseEditor.cs b/osu.Game/Tests/Visual/EditorTestCase.cs similarity index 85% rename from osu.Game/Tests/Visual/TestCaseEditor.cs rename to osu.Game/Tests/Visual/EditorTestCase.cs index 76eae7acea..ed2b47ae39 100644 --- a/osu.Game/Tests/Visual/TestCaseEditor.cs +++ b/osu.Game/Tests/Visual/EditorTestCase.cs @@ -11,13 +11,13 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual { - public abstract class TestCaseEditor : OsuTestCase + public abstract class EditorTestCase : OsuTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(Editor), typeof(EditorScreen) }; private readonly Ruleset ruleset; - protected TestCaseEditor(Ruleset ruleset) + protected EditorTestCase(Ruleset ruleset) { this.ruleset = ruleset; } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c99ccd6945..7214a31639 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -902,7 +902,7 @@ - + From e97349fd63a96c26a36b0d7fe239ecf6ad51baa1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Mar 2018 16:00:56 +0900 Subject: [PATCH 57/58] Derive ScreenTestCase + use LoadComponentAsync --- osu.Game/Tests/Visual/EditorTestCase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/EditorTestCase.cs b/osu.Game/Tests/Visual/EditorTestCase.cs index ed2b47ae39..982a3c5d73 100644 --- a/osu.Game/Tests/Visual/EditorTestCase.cs +++ b/osu.Game/Tests/Visual/EditorTestCase.cs @@ -11,7 +11,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual { - public abstract class EditorTestCase : OsuTestCase + public abstract class EditorTestCase : ScreenTestCase { public override IReadOnlyList RequiredTypes => new[] { typeof(Editor), typeof(EditorScreen) }; @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual { osuGame.Beatmap.Value = new TestWorkingBeatmap(ruleset.RulesetInfo); - Child = new Editor(); + LoadComponentAsync(new Editor(), LoadScreen); } } } From ba44813c0007ac4d0099fc2466a40d1b3c8d1534 Mon Sep 17 00:00:00 2001 From: vperus Date: Tue, 13 Mar 2018 12:05:52 +0200 Subject: [PATCH 58/58] Fixed exit from game save username instead of email. Resolve #2156 --- osu.Game/Online/API/APIAccess.cs | 1 - osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 1325179e0d..bab53cb462 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -125,7 +125,6 @@ namespace osu.Game.Online.API userReq.Success += u => { LocalUser.Value = u; - Username = LocalUser.Value.Username; failureCount = 0; //we're connected! diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index c2dfea9a08..16586adc0c 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.Toolbar avatar.User = new User(); break; case APIState.Online: - Text = api.Username; + Text = api.LocalUser.Value.Username; avatar.User = api.LocalUser; break; }