From f99eff11926d9c70e18b63e4aaa8952cd6721e5f Mon Sep 17 00:00:00 2001 From: Joehu Date: Sat, 15 Sep 2018 07:30:11 -0700 Subject: [PATCH 01/93] Use consistent terminology format --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 4 ++-- osu.Game.Rulesets.Taiko/TaikoInputManager.cs | 8 ++++---- osu.Game/Input/Bindings/GlobalActionContainer.cs | 8 ++++---- .../Overlays/Settings/Sections/Audio/OffsetSettings.cs | 2 +- .../Overlays/Settings/Sections/Audio/VolumeSettings.cs | 2 +- .../Overlays/Settings/Sections/Input/KeyboardSettings.cs | 2 +- .../Overlays/Settings/Sections/Input/MouseSettings.cs | 4 ++-- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs | 8 ++++---- osu.Game/Screens/Edit/Components/PlaybackControl.cs | 2 +- .../Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs | 4 ++-- osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs | 2 +- osu.Game/Screens/Select/Filter/GroupMode.cs | 4 ++-- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- .../Storyboards/Drawables/DrawableStoryboardSample.cs | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index e7bbe755a0..b734f52fd1 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -48,10 +48,10 @@ namespace osu.Game.Rulesets.Osu public enum OsuAction { - [Description("Left Button")] + [Description("Left button")] LeftButton, - [Description("Right Button")] + [Description("Right button")] RightButton } } diff --git a/osu.Game.Rulesets.Taiko/TaikoInputManager.cs b/osu.Game.Rulesets.Taiko/TaikoInputManager.cs index dc683ae2f5..3b430e7ad1 100644 --- a/osu.Game.Rulesets.Taiko/TaikoInputManager.cs +++ b/osu.Game.Rulesets.Taiko/TaikoInputManager.cs @@ -17,13 +17,13 @@ namespace osu.Game.Rulesets.Taiko public enum TaikoAction { - [Description("Left (Rim)")] + [Description("Left (rim)")] LeftRim, - [Description("Left (Centre)")] + [Description("Left (centre)")] LeftCentre, - [Description("Right (Centre)")] + [Description("Right (centre)")] RightCentre, - [Description("Right (Rim)")] + [Description("Right (rim)")] RightRim } } diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index b21deff509..2f5f1aea3f 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -71,17 +71,17 @@ namespace osu.Game.Input.Bindings ToggleSettings, [Description("Toggle osu!direct")] ToggleDirect, - [Description("Increase Volume")] + [Description("Increase volume")] IncreaseVolume, - [Description("Decrease Volume")] + [Description("Decrease volume")] DecreaseVolume, [Description("Toggle mute")] ToggleMute, // In-Game Keybindings - [Description("Skip Cutscene")] + [Description("Skip cutscene")] SkipCutscene, - [Description("Quick Retry (Hold)")] + [Description("Quick retry (hold)")] QuickRetry, [Description("Take screenshot")] diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index 0fe41327db..da96c6ef30 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { new SettingsSlider { - LabelText = "Audio Offset", + LabelText = "Audio offset", Bindable = config.GetBindable(OsuSetting.AudioOffset), KeyboardStep = 1f }, diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index 369c751448..fa4a714ba3 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio Children = new Drawable[] { new SettingsSlider { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.01f }, - new SettingsSlider { LabelText = "Master (Window Inactive)", Bindable = config.GetBindable(OsuSetting.VolumeInactive), KeyboardStep = 0.01f }, + new SettingsSlider { LabelText = "Master (window inactive)", Bindable = config.GetBindable(OsuSetting.VolumeInactive), KeyboardStep = 0.01f }, new SettingsSlider { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.01f }, new SettingsSlider { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.01f }, }; diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs index 456d1c9a2f..51b0296ca4 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyboardSettings.cs @@ -15,7 +15,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { new SettingsButton { - Text = "Key Configuration", + Text = "Key configuration", Action = keyConfig.ToggleVisibility }, }; diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index 71ab4d3782..a3ed66d547 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -26,12 +26,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input { new SettingsCheckbox { - LabelText = "Raw Input", + LabelText = "Raw input", Bindable = rawInputToggle }, sensitivity = new SensitivitySetting { - LabelText = "Cursor Sensitivity", + LabelText = "Cursor sensitivity", Bindable = config.GetBindable(FrameworkSetting.CursorSensitivity) }, new SettingsCheckbox diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index a274d9b12f..c7030b9db9 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Objects.Drawables public event Action ApplyCustomUpdateState; /// - /// Plays all the hitsounds for this . + /// Plays all the hit sounds for this . /// public void PlaySamples() => Samples?.Play(); diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs index 4fe727cb84..d0db8f8835 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingDirection.cs @@ -6,19 +6,19 @@ namespace osu.Game.Rulesets.UI.Scrolling public enum ScrollingDirection { /// - /// Hitobjects will scroll vertically from the bottom of the hitobject container. + /// Hit objects will scroll vertically from the bottom of the hitobject container. /// Up, /// - /// Hitobjects will scroll vertically from the top of the hitobject container. + /// Hit objects will scroll vertically from the top of the hitobject container. /// Down, /// - /// Hitobjects will scroll horizontally from the right of the hitobject container. + /// Hit objects will scroll horizontally from the right of the hitobject container. /// Left, /// - /// Hitobjects will scroll horizontally from the left of the hitobject container. + /// Hit objects will scroll horizontally from the left of the hitobject container. /// Right } diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 6cd7fd52d4..6d5bfe9ae6 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Edit.Components new OsuSpriteText { Origin = Anchor.BottomLeft, - Text = "Playback Speed", + Text = "Playback speed", RelativePositionAxes = Axes.Y, Y = 0.5f, Padding = new MarginPadding { Left = 45 } diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs index 006317e57e..ecf760be8e 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs @@ -59,8 +59,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Timeline Spacing = new Vector2(0, 4), Children = new[] { - hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hitobjects" }, - hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hitsounds" }, + hitObjectsCheckbox = new OsuCheckbox { LabelText = "Hit objects" }, + hitSoundsCheckbox = new OsuCheckbox { LabelText = "Hit sounds" }, waveformCheckbox = new OsuCheckbox { LabelText = "Waveform" } } } diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 439e344020..f762597e81 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play.PlayerSettings }, showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" }, beatmapSkinsToggle = new PlayerCheckbox { LabelText = "Beatmap skins" }, - beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hitsounds" } + beatmapHitsoundsToggle = new PlayerCheckbox { LabelText = "Beatmap hit sounds" } }; } diff --git a/osu.Game/Screens/Select/Filter/GroupMode.cs b/osu.Game/Screens/Select/Filter/GroupMode.cs index 6e57843dfc..b3bd73ee59 100644 --- a/osu.Game/Screens/Select/Filter/GroupMode.cs +++ b/osu.Game/Screens/Select/Filter/GroupMode.cs @@ -21,8 +21,8 @@ namespace osu.Game.Screens.Select.Filter DateAdded, [Description("Difficulty")] Difficulty, - [Description("Favorites")] - Favorites, + [Description("Favourites")] + Favourites, [Description("Length")] Length, [Description("My Maps")] diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 2c43b333aa..917a08d172 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.fa_times_circle_o, colours.Purple, null, Key.Number1); BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.fa_eraser, colours.Purple, null, Key.Number2); - BeatmapOptions.AddButton(@"Edit", @"Beatmap", FontAwesome.fa_pencil, colours.Yellow, () => + BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () => { ValidForResume = false; Push(new Editor()); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index efdf55e477..2d497a22a4 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -205,7 +205,7 @@ namespace osu.Game.Screens.Select Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3); - BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); + BeatmapOptions.AddButton(@"Delete", @"beatmapset", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); } if (this.beatmaps == null) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs index cdec8c042f..4f469ae593 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs @@ -41,7 +41,7 @@ namespace osu.Game.Storyboards.Drawables { base.Update(); - // TODO: this logic will need to be consolidated with other game samples like hitsounds. + // TODO: this logic will need to be consolidated with other game samples like hit sounds. if (Time.Current < sample.Time) { // We've rewound before the start time of the sample From d855e5957a331eadd9b798f54d22d4cd27445b56 Mon Sep 17 00:00:00 2001 From: Fayne Aldan Date: Sat, 15 Sep 2018 16:16:37 -0600 Subject: [PATCH 02/93] Don't wiggle repeat points independently --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 2e601c9078..e0a93453ce 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -37,6 +37,11 @@ namespace osu.Game.Rulesets.Osu.Mods var osuObject = (OsuHitObject)drawable.HitObject; Vector2 origin = drawable.Position; + // Wiggle the repeat points with the slider instead of independently. + // Also fixes an issue with repeat points being positioned incorrectly. + if (osuObject is RepeatPoint) + return; + Random objRand = new Random((int)osuObject.StartTime); // Wiggle all objects during TimePreempt From 826dc6ceb71224f8c9261b5eea00e77a1d4a7358 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 14:02:32 +0900 Subject: [PATCH 03/93] Make Playfield not a ScalableContainer --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 46 +++++---- .../UI/ScalingContainer.cs | 29 ++++++ .../Edit/OsuHitObjectComposer.cs | 18 +++- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 46 ++++++--- .../UI/OsuRulesetContainer.cs | 7 -- osu.Game.Rulesets.Osu/UI/ScalingContainer.cs | 29 ++++++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- osu.Game/Rulesets/UI/Playfield.cs | 20 ++-- osu.Game/Rulesets/UI/ScalableContainer.cs | 99 ------------------- .../UI/Scrolling/ScrollingPlayfield.cs | 14 --- 10 files changed, 143 insertions(+), 167 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/ScalingContainer.cs create mode 100644 osu.Game.Rulesets.Osu/UI/ScalingContainer.cs delete mode 100644 osu.Game/Rulesets/UI/ScalableContainer.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 102ec7fb3b..ecd1142b52 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -25,7 +25,6 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; public CatchPlayfield(BeatmapDifficulty difficulty, Func> getVisualRepresentation) - : base(BASE_WIDTH) { Direction.Value = ScrollingDirection.Down; @@ -34,27 +33,36 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.TopCentre; Origin = Anchor.TopCentre; - base.Content.Anchor = Anchor.BottomLeft; - base.Content.Origin = Anchor.BottomLeft; - - base.Content.AddRange(new Drawable[] + InternalChild = new Container { - explodingFruitContainer = new Container + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + FillAspectRatio = 4f / 3, + Child = new ScalingContainer(BASE_WIDTH) { RelativeSizeAxes = Axes.Both, - }, - catcherArea = new CatcherArea(difficulty) - { - GetVisualRepresentation = getVisualRepresentation, - ExplodingFruitTarget = explodingFruitContainer, - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft, - }, - content = new Container - { - RelativeSizeAxes = Axes.Both, - }, - }); + Children = new Drawable[] + { + explodingFruitContainer = new Container + { + RelativeSizeAxes = Axes.Both, + }, + catcherArea = new CatcherArea(difficulty) + { + GetVisualRepresentation = getVisualRepresentation, + ExplodingFruitTarget = explodingFruitContainer, + Anchor = Anchor.BottomLeft, + Origin = Anchor.TopLeft, + }, + content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + } + } + }; } public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.AttemptCatch(obj); diff --git a/osu.Game.Rulesets.Catch/UI/ScalingContainer.cs b/osu.Game.Rulesets.Catch/UI/ScalingContainer.cs new file mode 100644 index 0000000000..a2011dcc6f --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/ScalingContainer.cs @@ -0,0 +1,29 @@ +// 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 OpenTK; + +namespace osu.Game.Rulesets.Catch.UI +{ + /// + /// A which scales its content relative to a target width. + /// + public class ScalingContainer : Container + { + private readonly float targetWidth; + + public ScalingContainer(float targetWidth) + { + this.targetWidth = targetWidth; + } + + protected override void Update() + { + base.Update(); + + Scale = new Vector2(Parent.ChildSize.X / targetWidth); + Size = Vector2.Divide(Vector2.One, Scale); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index dce1fc2851..bec7d1fe26 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; @@ -31,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit new HitObjectCompositionTool() }; - protected override ScalableContainer CreateLayerContainer() => new ScalableContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both }; + protected override Container CreateLayerContainer() => new LayerContainer(); public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) { @@ -45,5 +46,20 @@ namespace osu.Game.Rulesets.Osu.Edit return base.CreateMaskFor(hitObject); } + + private class LayerContainer : Container + { + protected override Container Content => content; + private readonly Container content; + + public LayerContainer() + { + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + FillAspectRatio = 4f / 3; + + Child = content = new ScalingContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both }; + } + } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 61937a535c..b6e4ae62a9 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -20,32 +20,46 @@ namespace osu.Game.Rulesets.Osu.UI private readonly JudgementContainer judgementLayer; private readonly ConnectionRenderer connectionLayer; + private readonly Container content; + protected override Container Content => content; + public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); public OsuPlayfield() - : base(BASE_SIZE.X) { Anchor = Anchor.Centre; Origin = Anchor.Centre; - AddRange(new Drawable[] + InternalChild = new Container { - connectionLayer = new FollowPointRenderer + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + FillAspectRatio = 4f / 3, + Child = content = new ScalingContainer(BASE_SIZE.X) { RelativeSizeAxes = Axes.Both, - Depth = 2, - }, - judgementLayer = new JudgementContainer - { - RelativeSizeAxes = Axes.Both, - Depth = 1, - }, - approachCircles = new Container - { - RelativeSizeAxes = Axes.Both, - Depth = -1, - }, - }); + Children = new Drawable[] + { + connectionLayer = new FollowPointRenderer + { + RelativeSizeAxes = Axes.Both, + Depth = 2, + }, + judgementLayer = new JudgementContainer + { + RelativeSizeAxes = Axes.Both, + Depth = 1, + }, + approachCircles = new Container + { + RelativeSizeAxes = Axes.Both, + Depth = -1, + }, + } + } + }; } public override void Add(DrawableHitObject h) diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 4bc6992445..0ea8d3ede8 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -4,7 +4,6 @@ using System.Linq; using osu.Framework.Graphics.Cursor; using osu.Framework.Input; -using OpenTK; using osu.Game.Beatmaps; using osu.Game.Input.Handlers; using osu.Game.Rulesets.Objects.Drawables; @@ -58,12 +57,6 @@ namespace osu.Game.Rulesets.Osu.UI } } - protected override Vector2 GetAspectAdjustedSize() - { - var aspectSize = DrawSize.X * 0.75f < DrawSize.Y ? new Vector2(DrawSize.X, DrawSize.X * 0.75f) : new Vector2(DrawSize.Y * 4f / 3f, DrawSize.Y); - return new Vector2(aspectSize.X / DrawSize.X, aspectSize.Y / DrawSize.Y); - } - protected override CursorContainer CreateCursor() => new GameplayCursor(); } } diff --git a/osu.Game.Rulesets.Osu/UI/ScalingContainer.cs b/osu.Game.Rulesets.Osu/UI/ScalingContainer.cs new file mode 100644 index 0000000000..0a9bec67fb --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/ScalingContainer.cs @@ -0,0 +1,29 @@ +// 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 OpenTK; + +namespace osu.Game.Rulesets.Osu.UI +{ + /// + /// A which scales its content relative to a target width. + /// + public class ScalingContainer : Container + { + private readonly float targetWidth; + + public ScalingContainer(float targetWidth) + { + this.targetWidth = targetWidth; + } + + protected override void Update() + { + base.Update(); + + Scale = new Vector2(Parent.ChildSize.X / targetWidth); + Size = Vector2.Divide(Vector2.One, Scale); + } + } +} diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index a3253250f2..8060ac742a 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -165,6 +165,6 @@ namespace osu.Game.Rulesets.Edit /// /// Creates a which provides a layer above or below the . /// - protected virtual ScalableContainer CreateLayerContainer() => new ScalableContainer { RelativeSizeAxes = Axes.Both }; + protected virtual Container CreateLayerContainer() => new Container { RelativeSizeAxes = Axes.Both }; } } diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index e090a18eda..a8dc096a1d 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -9,18 +9,25 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Configuration; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; +using OpenTK; namespace osu.Game.Rulesets.UI { - public abstract class Playfield : ScalableContainer + public abstract class Playfield : Container { /// /// The contained in this Playfield. /// public HitObjectContainer HitObjectContainer { get; private set; } + /// + /// A function that converts gamefield coordinates to screen space. + /// + public Func GamefieldToScreenSpace => HitObjectContainer.ToScreenSpace; + /// /// All the s contained in this and all . /// @@ -39,16 +46,9 @@ namespace osu.Game.Rulesets.UI public readonly BindableBool DisplayJudgements = new BindableBool(true); /// - /// A container for keeping track of DrawableHitObjects. + /// Creates a new . /// - /// The width to scale the internal coordinate space to. - /// May be null if scaling based on is desired. If is also null, no scaling will occur. - /// - /// The height to scale the internal coordinate space to. - /// May be null if scaling based on is desired. If is also null, no scaling will occur. - /// - protected Playfield(float? customWidth = null, float? customHeight = null) - : base(customWidth, customHeight) + protected Playfield() { RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game/Rulesets/UI/ScalableContainer.cs b/osu.Game/Rulesets/UI/ScalableContainer.cs deleted file mode 100644 index 5ee03be7ee..0000000000 --- a/osu.Game/Rulesets/UI/ScalableContainer.cs +++ /dev/null @@ -1,99 +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 osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using OpenTK; - -namespace osu.Game.Rulesets.UI -{ - /// - /// A which can have its internal coordinate system scaled to a specific size. - /// - public class ScalableContainer : Container - { - /// - /// A function that converts coordinates from gamefield to screen space. - /// - public Func GamefieldToScreenSpace => scaledContent.GamefieldToScreenSpace; - - /// - /// The scaled content. - /// - private readonly ScaledContainer scaledContent; - protected override Container Content => scaledContent; - - /// - /// A which can have its internal coordinate system scaled to a specific size. - /// - /// The width to scale the internal coordinate space to. - /// May be null if scaling based on is desired. If is also null, no scaling will occur. - /// - /// The height to scale the internal coordinate space to. - /// May be null if scaling based on is desired. If is also null, no scaling will occur. - /// - public ScalableContainer(float? customWidth = null, float? customHeight = null) - { - AddInternal(scaledContent = new ScaledContainer - { - CustomWidth = customWidth, - CustomHeight = customHeight, - RelativeSizeAxes = Axes.Both, - }); - } - - private class ScaledContainer : Container - { - /// - /// A function that converts coordinates from gamefield to screen space. - /// - public Func GamefieldToScreenSpace => content.ToScreenSpace; - - /// - /// The value to scale the width of the content to match. - /// If null, is used. - /// - public float? CustomWidth; - - /// - /// The value to scale the height of the content to match. - /// if null, is used. - /// - public float? CustomHeight; - - private readonly Container content; - protected override Container Content => content; - - public ScaledContainer() - { - AddInternal(content = new Container { RelativeSizeAxes = Axes.Both }); - } - - protected override void Update() - { - base.Update(); - - content.Scale = sizeScale; - content.Size = Vector2.Divide(Vector2.One, sizeScale); - } - - /// - /// The scale that is required for the size of the content to match and . - /// - private Vector2 sizeScale - { - get - { - if (CustomWidth.HasValue && CustomHeight.HasValue) - return Vector2.Divide(DrawSize, new Vector2(CustomWidth.Value, CustomHeight.Value)); - if (CustomWidth.HasValue) - return new Vector2(DrawSize.X / CustomWidth.Value); - if (CustomHeight.HasValue) - return new Vector2(DrawSize.Y / CustomHeight.Value); - return Vector2.One; - } - } - } - } -} diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index ec73c0fb14..b555b6616a 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -62,20 +62,6 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly Bindable Direction = new Bindable(); - /// - /// Creates a new . - /// - /// The width to scale the internal coordinate space to. - /// May be null if scaling based on is desired. If is also null, no scaling will occur. - /// - /// The height to scale the internal coordinate space to. - /// May be null if scaling based on is desired. If is also null, no scaling will occur. - /// - protected ScrollingPlayfield(float? customWidth = null, float? customHeight = null) - : base(customWidth, customHeight) - { - } - [BackgroundDependencyLoader] private void load() { From 368ceec47cb86e696c439aecdd4e15753d68f433 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 14:35:50 +0900 Subject: [PATCH 04/93] Simplify creation of a playfield --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 8 +------ osu.Game.Rulesets.Mania/UI/Column.cs | 7 +++--- .../UI/Components/ColumnHitObjectArea.cs | 24 ++++++++----------- .../UI/ManiaScrollingPlayfield.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaStage.cs | 4 ++-- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 6 ++--- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +++---- .../Visual/TestCaseScrollingHitObjects.cs | 19 ++++++++++----- osu.Game/Rulesets/UI/HitObjectContainer.cs | 5 ++++ osu.Game/Rulesets/UI/Playfield.cs | 23 +++++++++--------- 10 files changed, 52 insertions(+), 54 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index ecd1142b52..aa3fcefd9b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -17,9 +17,6 @@ namespace osu.Game.Rulesets.Catch.UI { public const float BASE_WIDTH = 512; - protected override Container Content => content; - private readonly Container content; - private readonly CatcherArea catcherArea; protected override bool UserScrollSpeedAdjustment => false; @@ -56,10 +53,7 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.BottomLeft, Origin = Anchor.TopLeft, }, - content = new Container - { - RelativeSizeAxes = Axes.Both, - }, + HitObjectContainer } } }; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index d489d48fc3..09976e5994 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -30,8 +30,6 @@ namespace osu.Game.Rulesets.Mania.UI internal readonly Container TopLevelContainer; private readonly Container explosionContainer; - protected override Container Content => hitObjectArea; - public Column() { RelativeSizeAxes = Axes.Y; @@ -54,7 +52,10 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - hitObjectArea = new ColumnHitObjectArea { RelativeSizeAxes = Axes.Both }, + hitObjectArea = new ColumnHitObjectArea(HitObjectContainer) + { + RelativeSizeAxes = Axes.Both, + }, explosionContainer = new Container { Name = "Hit explosions", diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index b5dfb0949a..5a4adfd72e 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -8,28 +8,24 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using OpenTK.Graphics; namespace osu.Game.Rulesets.Mania.UI.Components { - public class ColumnHitObjectArea : Container, IHasAccentColour + public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour { private const float hit_target_height = 10; private const float hit_target_bar_height = 2; - private Container content; - protected override Container Content => content; - private readonly IBindable direction = new Bindable(); - private Container hitTargetLine; + private readonly Container hitTargetLine; + private readonly Drawable hitTargetBar; - [BackgroundDependencyLoader] - private void load(IScrollingInfo scrollingInfo) + public ColumnHitObjectArea(HitObjectContainer hitObjectContainer) { - Drawable hitTargetBar; - InternalChildren = new[] { hitTargetBar = new Box @@ -45,13 +41,13 @@ namespace osu.Game.Rulesets.Mania.UI.Components Masking = true, Child = new Box { RelativeSizeAxes = Axes.Both } }, - content = new Container - { - Name = "Hit objects", - RelativeSizeAxes = Axes.Both, - }, + hitObjectContainer }; + } + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(direction => { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs index 4d6c5a747a..8ee0fbf7fe 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaScrollingPlayfield.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.UI { - public class ManiaScrollingPlayfield : ScrollingPlayfield + public abstract class ManiaScrollingPlayfield : ScrollingPlayfield { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs index f292d5ff16..8cf49686b9 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs @@ -30,8 +30,7 @@ namespace osu.Game.Rulesets.Mania.UI public IReadOnlyList Columns => columnFlow.Children; private readonly FillFlowContainer columnFlow; - protected override Container Content => barLineContainer; - private readonly Container barLineContainer; + private readonly Container barLineContainer; public Container Judgements => judgements; private readonly JudgementContainer judgements; @@ -105,6 +104,7 @@ namespace osu.Game.Rulesets.Mania.UI Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Y, + Child = HitObjectContainer } }, judgements = new JudgementContainer diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index b6e4ae62a9..d3a4008691 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -20,9 +20,6 @@ namespace osu.Game.Rulesets.Osu.UI private readonly JudgementContainer judgementLayer; private readonly ConnectionRenderer connectionLayer; - private readonly Container content; - protected override Container Content => content; - public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); public OsuPlayfield() @@ -37,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, FillAspectRatio = 4f / 3, - Child = content = new ScalingContainer(BASE_SIZE.X) + Child = new ScalingContainer(BASE_SIZE.X) { RelativeSizeAxes = Axes.Both, Children = new Drawable[] @@ -52,6 +49,7 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, Depth = 1, }, + HitObjectContainer, approachCircles = new Container { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 325beb38a5..6c443a2ac1 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -44,9 +44,6 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Container kiaiExplosionContainer; private readonly JudgementContainer judgementContainer; - protected override Container Content => content; - private readonly Container content; - private readonly Container topLevelHitContainer; private readonly Container barlineContainer; @@ -118,12 +115,13 @@ namespace osu.Game.Rulesets.Taiko.UI RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Left = HIT_TARGET_OFFSET } }, - content = new Container + new Container { Name = "Hit objects", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Masking = true + Masking = true, + Child = HitObjectContainer }, kiaiExplosionContainer = new Container { diff --git a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs index bbc9d2b860..b254325472 100644 --- a/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/TestCaseScrollingHitObjects.cs @@ -121,14 +121,21 @@ namespace osu.Game.Tests.Visual Direction = direction; Padding = new MarginPadding(2); - Content.Masking = true; - AddInternal(new Box + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Alpha = 0.5f, - Depth = float.MaxValue - }); + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.5f, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = HitObjectContainer + } + }; } } diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index af18d98561..261132c56b 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -14,6 +14,11 @@ namespace osu.Game.Rulesets.UI public IEnumerable Objects => InternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); public IEnumerable AliveObjects => AliveInternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); + public HitObjectContainer() + { + RelativeSizeAxes = Axes.Both; + } + public virtual void Add(DrawableHitObject hitObject) => AddInternal(hitObject); public virtual bool Remove(DrawableHitObject hitObject) => RemoveInternal(hitObject); diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index a8dc096a1d..f5db0cd3ce 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -16,12 +16,14 @@ using OpenTK; namespace osu.Game.Rulesets.UI { - public abstract class Playfield : Container + public abstract class Playfield : CompositeDrawable { /// /// The contained in this Playfield. /// - public HitObjectContainer HitObjectContainer { get; private set; } + public HitObjectContainer HitObjectContainer => hitObjectContainerLazy.Value; + + private readonly Lazy hitObjectContainerLazy; /// /// A function that converts gamefield coordinates to screen space. @@ -51,6 +53,8 @@ namespace osu.Game.Rulesets.UI protected Playfield() { RelativeSizeAxes = Axes.Both; + + hitObjectContainerLazy = new Lazy(CreateHitObjectContainer); } private WorkingBeatmap beatmap; @@ -59,11 +63,6 @@ namespace osu.Game.Rulesets.UI private void load(IBindableBeatmap beatmap) { this.beatmap = beatmap.Value; - - HitObjectContainer = CreateHitObjectContainer(); - HitObjectContainer.RelativeSizeAxes = Axes.Both; - - Add(HitObjectContainer); } /// @@ -94,11 +93,6 @@ namespace osu.Game.Rulesets.UI nestedPlayfields.Value.Add(otherPlayfield); } - /// - /// Creates the container that will be used to contain the s. - /// - protected virtual HitObjectContainer CreateHitObjectContainer() => new HitObjectContainer(); - protected override void Update() { base.Update(); @@ -108,5 +102,10 @@ namespace osu.Game.Rulesets.UI if (mod is IUpdatableByPlayfield updatable) updatable.Update(this); } + + /// + /// Creates the container that will be used to contain the s. + /// + protected virtual HitObjectContainer CreateHitObjectContainer() => new HitObjectContainer(); } } From a166d03ede7c3027b4d24698024f953b56906cd4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 14:43:17 +0900 Subject: [PATCH 05/93] Remove duplicate implementation of the Osu playfield layer --- .../Edit/OsuHitObjectComposer.cs | 17 +------ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 42 +++++++--------- osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs | 49 +++++++++++++++++++ osu.Game.Rulesets.Osu/UI/ScalingContainer.cs | 29 ----------- 4 files changed, 67 insertions(+), 70 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs delete mode 100644 osu.Game.Rulesets.Osu/UI/ScalingContainer.cs diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index bec7d1fe26..ad92ea15d4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit new HitObjectCompositionTool() }; - protected override Container CreateLayerContainer() => new LayerContainer(); + protected override Container CreateLayerContainer() => new PlayfieldLayer { RelativeSizeAxes = Axes.Both }; public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) { @@ -46,20 +46,5 @@ namespace osu.Game.Rulesets.Osu.Edit return base.CreateMaskFor(hitObject); } - - private class LayerContainer : Container - { - protected override Container Content => content; - private readonly Container content; - - public LayerContainer() - { - RelativeSizeAxes = Axes.Both; - FillMode = FillMode.Fit; - FillAspectRatio = 4f / 3; - - Child = content = new ScalingContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both }; - } - } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index d3a4008691..9b3a6a7131 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -27,35 +27,27 @@ namespace osu.Game.Rulesets.Osu.UI Anchor = Anchor.Centre; Origin = Anchor.Centre; - InternalChild = new Container + InternalChild = new PlayfieldLayer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - FillAspectRatio = 4f / 3, - Child = new ScalingContainer(BASE_SIZE.X) + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + connectionLayer = new FollowPointRenderer { - connectionLayer = new FollowPointRenderer - { - RelativeSizeAxes = Axes.Both, - Depth = 2, - }, - judgementLayer = new JudgementContainer - { - RelativeSizeAxes = Axes.Both, - Depth = 1, - }, - HitObjectContainer, - approachCircles = new Container - { - RelativeSizeAxes = Axes.Both, - Depth = -1, - }, - } + RelativeSizeAxes = Axes.Both, + Depth = 2, + }, + judgementLayer = new JudgementContainer + { + RelativeSizeAxes = Axes.Both, + Depth = 1, + }, + HitObjectContainer, + approachCircles = new Container + { + RelativeSizeAxes = Axes.Both, + Depth = -1, + }, } }; } diff --git a/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs new file mode 100644 index 0000000000..4d1eea27c9 --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs @@ -0,0 +1,49 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.UI +{ + public class PlayfieldLayer : Container + { + protected override Container Content => content; + private readonly Container content; + + public PlayfieldLayer() + { + InternalChild = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + FillAspectRatio = 4f / 3, + Child = content = new ScalingContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both } + }; + } + + /// + /// A which scales its content relative to a target width. + /// + private class ScalingContainer : Container + { + private readonly float targetWidth; + + public ScalingContainer(float targetWidth) + { + this.targetWidth = targetWidth; + } + + protected override void Update() + { + base.Update(); + + Scale = new Vector2(Parent.ChildSize.X / targetWidth); + Size = Vector2.Divide(Vector2.One, Scale); + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/UI/ScalingContainer.cs b/osu.Game.Rulesets.Osu/UI/ScalingContainer.cs deleted file mode 100644 index 0a9bec67fb..0000000000 --- a/osu.Game.Rulesets.Osu/UI/ScalingContainer.cs +++ /dev/null @@ -1,29 +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.Graphics.Containers; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.UI -{ - /// - /// A which scales its content relative to a target width. - /// - public class ScalingContainer : Container - { - private readonly float targetWidth; - - public ScalingContainer(float targetWidth) - { - this.targetWidth = targetWidth; - } - - protected override void Update() - { - base.Update(); - - Scale = new Vector2(Parent.ChildSize.X / targetWidth); - Size = Vector2.Divide(Vector2.One, Scale); - } - } -} From 26094ea3254c3c58e09ab9698b91e8685c300ecd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 15:01:58 +0900 Subject: [PATCH 06/93] Simplify + rename playfield layers in Osu/Catch --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- .../UI/{ScalingContainer.cs => PlayfieldLayer.cs} | 14 ++------------ osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs | 11 ++--------- 3 files changed, 5 insertions(+), 22 deletions(-) rename osu.Game.Rulesets.Catch/UI/{ScalingContainer.cs => PlayfieldLayer.cs} (50%) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index aa3fcefd9b..a926054b24 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.UI RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, FillAspectRatio = 4f / 3, - Child = new ScalingContainer(BASE_WIDTH) + Child = new PlayfieldLayer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game.Rulesets.Catch/UI/ScalingContainer.cs b/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs similarity index 50% rename from osu.Game.Rulesets.Catch/UI/ScalingContainer.cs rename to osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs index a2011dcc6f..c2cce6361d 100644 --- a/osu.Game.Rulesets.Catch/UI/ScalingContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs @@ -6,23 +6,13 @@ using OpenTK; namespace osu.Game.Rulesets.Catch.UI { - /// - /// A which scales its content relative to a target width. - /// - public class ScalingContainer : Container + public class PlayfieldLayer : Container { - private readonly float targetWidth; - - public ScalingContainer(float targetWidth) - { - this.targetWidth = targetWidth; - } - protected override void Update() { base.Update(); - Scale = new Vector2(Parent.ChildSize.X / targetWidth); + Scale = new Vector2(Parent.ChildSize.X / CatchPlayfield.BASE_WIDTH); Size = Vector2.Divide(Vector2.One, Scale); } } diff --git a/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs index 4d1eea27c9..a4c84e4905 100644 --- a/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs +++ b/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.UI RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, FillAspectRatio = 4f / 3, - Child = content = new ScalingContainer(OsuPlayfield.BASE_SIZE.X) { RelativeSizeAxes = Axes.Both } + Child = content = new ScalingContainer { RelativeSizeAxes = Axes.Both } }; } @@ -30,18 +30,11 @@ namespace osu.Game.Rulesets.Osu.UI /// private class ScalingContainer : Container { - private readonly float targetWidth; - - public ScalingContainer(float targetWidth) - { - this.targetWidth = targetWidth; - } - protected override void Update() { base.Update(); - Scale = new Vector2(Parent.ChildSize.X / targetWidth); + Scale = new Vector2(Parent.ChildSize.X / OsuPlayfield.BASE_SIZE.X); Size = Vector2.Divide(Vector2.One, Scale); } } From 0bc2bcaf1480d31ec1c22e7f631591ae2d0fb586 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 15:08:43 +0900 Subject: [PATCH 07/93] Remove GetAspectAdjustedSize() and PlayfieldArea --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 3 + .../UI/CatchRulesetContainer.cs | 3 - .../Edit/ManiaEditRulesetContainer.cs | 3 +- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 3 + .../UI/ManiaRulesetContainer.cs | 3 - .../Edit/OsuEditRulesetContainer.cs | 5 +- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 + osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs | 22 ++ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 252 +++++++++--------- .../UI/TaikoRulesetContainer.cs | 20 +- osu.Game/Rulesets/UI/RulesetContainer.cs | 21 -- 11 files changed, 164 insertions(+), 173 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index a926054b24..8b5ec2df9b 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; +using OpenTK; namespace osu.Game.Rulesets.Catch.UI { @@ -30,6 +31,8 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.TopCentre; Origin = Anchor.TopCentre; + Size = new Vector2(0.86f); // matches stable's vertical offset for catcher plate + InternalChild = new Container { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs index 1ac052de4d..bd0fec43a1 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchRulesetContainer.cs @@ -13,7 +13,6 @@ using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; -using OpenTK; namespace osu.Game.Rulesets.Catch.UI { @@ -32,8 +31,6 @@ namespace osu.Game.Rulesets.Catch.UI public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo); - protected override Vector2 PlayfieldArea => new Vector2(0.86f); // matches stable's vertical offset for catcher plate - protected override DrawableHitObject GetVisualRepresentation(CatchHitObject h) { switch (h) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs index a01947a60b..138a2c0273 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditRulesetContainer.cs @@ -20,8 +20,7 @@ namespace osu.Game.Rulesets.Mania.Edit { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Size = Vector2.One }; - - protected override Vector2 PlayfieldArea => Vector2.One; } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 999f84ed8e..5c3a618a19 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects.Drawables; +using OpenTK; namespace osu.Game.Rulesets.Mania.UI { @@ -25,6 +26,8 @@ namespace osu.Game.Rulesets.Mania.UI if (stageDefinitions.Count <= 0) throw new ArgumentException("Can't have zero or fewer stages."); + Size = new Vector2(1, 0.8f); + GridContainer playfieldGrid; AddInternal(playfieldGrid = new GridContainer { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs index 09ebde2799..49874f6dc1 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaRulesetContainer.cs @@ -24,7 +24,6 @@ using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; -using OpenTK; namespace osu.Game.Rulesets.Mania.UI { @@ -110,8 +109,6 @@ namespace osu.Game.Rulesets.Mania.UI } } - protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); - protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs index 6efa16bf56..8571de39f4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuEditRulesetContainer.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics.Cursor; using osu.Game.Beatmaps; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; using OpenTK; namespace osu.Game.Rulesets.Osu.Edit @@ -15,8 +16,8 @@ namespace osu.Game.Rulesets.Osu.Edit { } - protected override Vector2 PlayfieldArea => Vector2.One; - protected override CursorContainer CreateCursor() => null; + + protected override Playfield CreatePlayfield() => new OsuPlayfield { Size = Vector2.One }; } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 9b3a6a7131..ae8dc7397d 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Osu.UI Anchor = Anchor.Centre; Origin = Anchor.Centre; + Size = new Vector2(0.75f); + InternalChild = new PlayfieldLayer { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs new file mode 100644 index 0000000000..c4e2f32c92 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics.Containers; +using OpenTK; + +namespace osu.Game.Rulesets.Taiko.UI +{ + public class PlayfieldLayer : Container + { + private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; + private const float default_aspect = 16f / 9f; + + protected override void Update() + { + base.Update(); + + float aspectAdjust = MathHelper.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect; + Size = new Vector2(1, default_relative_height * aspectAdjust); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 6c443a2ac1..82ab327993 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -58,139 +58,145 @@ namespace osu.Game.Rulesets.Taiko.UI { Direction.Value = ScrollingDirection.Left; - AddRangeInternal(new Drawable[] + InternalChild = new PlayfieldLayer { - backgroundContainer = new Container + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Name = "Transparent playfield background", - RelativeSizeAxes = Axes.Both, - Masking = true, - EdgeEffect = new EdgeEffectParameters + backgroundContainer = new Container { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.2f), - Radius = 5, - }, - Children = new Drawable[] - { - background = new Box + Name = "Transparent playfield background", + RelativeSizeAxes = Axes.Both, + Masking = true, + EdgeEffect = new EdgeEffectParameters { - RelativeSizeAxes = Axes.Both, - Alpha = 0.6f + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.2f), + Radius = 5, }, - } - }, - new Container - { - Name = "Right area", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = left_area_size }, - Children = new Drawable[] - { - new Container + Children = new Drawable[] { - Name = "Masked elements before hit objects", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Masking = true, - Children = new Drawable[] + background = new Box { - hitExplosionContainer = new Container - { - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Blending = BlendingMode.Additive, - }, - new HitTarget - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit - } - } - }, - barlineContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = HIT_TARGET_OFFSET } - }, - new Container - { - Name = "Hit objects", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Masking = true, - Child = HitObjectContainer - }, - kiaiExplosionContainer = new Container - { - Name = "Kiai hit explosions", - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Blending = BlendingMode.Additive - }, - judgementContainer = new JudgementContainer - { - Name = "Judgements", - RelativeSizeAxes = Axes.Y, - Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, - Blending = BlendingMode.Additive - }, - } - }, - overlayBackgroundContainer = new Container - { - Name = "Left overlay", - RelativeSizeAxes = Axes.Y, - Size = new Vector2(left_area_size, 1), - Children = new Drawable[] - { - overlayBackground = new Box - { - RelativeSizeAxes = Axes.Both, - }, - new InputDrum(controlPoints) - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Scale = new Vector2(0.9f), - Margin = new MarginPadding { Right = 20 } - }, - new Box - { - Anchor = Anchor.TopRight, - RelativeSizeAxes = Axes.Y, - Width = 10, - Colour = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)), - }, - } - }, - new Container - { - Name = "Border", - RelativeSizeAxes = Axes.Both, - Masking = true, - MaskingSmoothness = 0, - BorderThickness = 2, - AlwaysPresent = true, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true + RelativeSizeAxes = Axes.Both, + Alpha = 0.6f + }, } + }, + new Container + { + Name = "Right area", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = left_area_size }, + Children = new Drawable[] + { + new Container + { + Name = "Masked elements before hit objects", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, + Masking = true, + Children = new Drawable[] + { + hitExplosionContainer = new Container + { + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Blending = BlendingMode.Additive, + }, + new HitTarget + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit + } + } + }, + barlineContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = HIT_TARGET_OFFSET } + }, + new Container + { + Name = "Hit objects", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = HIT_TARGET_OFFSET }, + Masking = true, + Child = HitObjectContainer + }, + kiaiExplosionContainer = new Container + { + Name = "Kiai hit explosions", + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, + Blending = BlendingMode.Additive + }, + judgementContainer = new JudgementContainer + { + Name = "Judgements", + RelativeSizeAxes = Axes.Y, + Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, + Blending = BlendingMode.Additive + }, + } + }, + overlayBackgroundContainer = new Container + { + Name = "Left overlay", + RelativeSizeAxes = Axes.Y, + Size = new Vector2(left_area_size, 1), + Children = new Drawable[] + { + overlayBackground = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new InputDrum(controlPoints) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Scale = new Vector2(0.9f), + Margin = new MarginPadding { Right = 20 } + }, + new Box + { + Anchor = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = 10, + Colour = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)), + }, + } + }, + new Container + { + Name = "Border", + RelativeSizeAxes = Axes.Both, + Masking = true, + MaskingSmoothness = 0, + BorderThickness = 2, + AlwaysPresent = true, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }, + topLevelHitContainer = new Container + { + Name = "Top level hit objects", + RelativeSizeAxes = Axes.Both, } - }, - topLevelHitContainer = new Container - { - Name = "Top level hit objects", - RelativeSizeAxes = Axes.Both, } - }); + }; VisibleTimeRange.Value = 6000; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs index 229ab69ceb..3d08bffe0f 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoRulesetContainer.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; @@ -13,7 +12,6 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.Taiko.Replays; -using OpenTK; using System.Linq; using osu.Framework.Input; using osu.Game.Input.Handlers; @@ -74,27 +72,11 @@ namespace osu.Game.Rulesets.Taiko.UI } } - protected override Vector2 GetAspectAdjustedSize() - { - const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; - const float default_aspect = 16f / 9f; - - float aspectAdjust = MathHelper.Clamp(DrawWidth / DrawHeight, 0.4f, 4) / default_aspect; - - return new Vector2(1, default_relative_height * aspectAdjust); - } - - protected override Vector2 PlayfieldArea => Vector2.One; - public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this); public override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); - protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }; + protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo); protected override DrawableHitObject GetVisualRepresentation(TaikoHitObject h) { diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index a830803fb1..a23a5a78f7 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -22,7 +22,6 @@ using osu.Game.Overlays; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; -using OpenTK; namespace osu.Game.Rulesets.UI { @@ -309,26 +308,6 @@ namespace osu.Game.Rulesets.UI mod.ApplyToDrawableHitObjects(Playfield.HitObjectContainer.Objects); } - protected override void Update() - { - base.Update(); - - Playfield.Size = GetAspectAdjustedSize() * PlayfieldArea; - } - - /// - /// Computes the size of the in relative coordinate space after aspect adjustments. - /// - /// The aspect-adjusted size. - protected virtual Vector2 GetAspectAdjustedSize() => Vector2.One; - - /// - /// The area of this that is available for the to use. - /// Must be specified in relative coordinate space to this . - /// This affects the final size of the but does not affect the 's scale. - /// - protected virtual Vector2 PlayfieldArea => new Vector2(0.75f); // A sane default - /// /// Creates a DrawableHitObject from a HitObject. /// From c3fa7f167fbf701f961b516e3527969bc93b8149 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 15:53:06 +0900 Subject: [PATCH 08/93] Move aspect adjustments out of CatchPlayfield --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 34 ++++++++------------ osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs | 33 ++++++++++++++++--- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 8b5ec2df9b..b90b90f45a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -33,31 +33,23 @@ namespace osu.Game.Rulesets.Catch.UI Size = new Vector2(0.86f); // matches stable's vertical offset for catcher plate - InternalChild = new Container + InternalChild = new PlayfieldLayer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - FillAspectRatio = 4f / 3, - Child = new PlayfieldLayer + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + explodingFruitContainer = new Container { - explodingFruitContainer = new Container - { - RelativeSizeAxes = Axes.Both, - }, - catcherArea = new CatcherArea(difficulty) - { - GetVisualRepresentation = getVisualRepresentation, - ExplodingFruitTarget = explodingFruitContainer, - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopLeft, - }, - HitObjectContainer - } + RelativeSizeAxes = Axes.Both, + }, + catcherArea = new CatcherArea(difficulty) + { + GetVisualRepresentation = getVisualRepresentation, + ExplodingFruitTarget = explodingFruitContainer, + Anchor = Anchor.BottomLeft, + Origin = Anchor.TopLeft, + }, + HitObjectContainer } }; } diff --git a/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs index c2cce6361d..d167dc59cc 100644 --- a/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs +++ b/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.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.Graphics; using osu.Framework.Graphics.Containers; using OpenTK; @@ -8,12 +9,34 @@ namespace osu.Game.Rulesets.Catch.UI { public class PlayfieldLayer : Container { - protected override void Update() - { - base.Update(); + protected override Container Content => content; + private readonly Container content; - Scale = new Vector2(Parent.ChildSize.X / CatchPlayfield.BASE_WIDTH); - Size = Vector2.Divide(Vector2.One, Scale); + public PlayfieldLayer() + { + InternalChild = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + FillAspectRatio = 4f / 3, + Child = content = new ScalingContainer { RelativeSizeAxes = Axes.Both } + }; + } + + /// + /// A which scales its content relative to a target width. + /// + private class ScalingContainer : Container + { + protected override void Update() + { + base.Update(); + + Scale = new Vector2(Parent.ChildSize.X / CatchPlayfield.BASE_WIDTH); + Size = Vector2.Divide(Vector2.One, Scale); + } } } } From cdeb4913c420591de7761c4e851ccef3437b2efa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 21 Sep 2018 15:11:12 +0900 Subject: [PATCH 09/93] Adjust catcher size to match stable --- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index be56ccf8c1..06453ac32d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatcherArea : Container { - public const float CATCHER_SIZE = 84; + public const float CATCHER_SIZE = 100; protected readonly Catcher MovableCatcher; From b68eeae777858fbc14670386615abc9790174074 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 1 Oct 2018 18:12:26 +0900 Subject: [PATCH 10/93] Fix scrolling rulesets not accounting for slider multiplier --- .../Rulesets/Timing/MultiplierControlPoint.cs | 21 +++++++------------ .../UI/Scrolling/ScrollingRulesetContainer.cs | 20 ++---------------- 2 files changed, 9 insertions(+), 32 deletions(-) diff --git a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs index a5bd6bfde7..4988bac5ce 100644 --- a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs +++ b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs @@ -18,9 +18,14 @@ namespace osu.Game.Rulesets.Timing public double StartTime; /// - /// The multiplier which this provides. + /// The aggregate multiplier which this provides. /// - public double Multiplier => 1000 / TimingPoint.BeatLength * DifficultyPoint.SpeedMultiplier; + public double Multiplier => Velocity * DifficultyPoint.SpeedMultiplier * 1000 / TimingPoint.BeatLength; + + /// + /// The velocity multiplier. + /// + public double Velocity = 1; /// /// The that provides the timing information for this . @@ -48,18 +53,6 @@ namespace osu.Game.Rulesets.Timing StartTime = startTime; } - /// - /// Creates a by copying another . - /// - /// The start time of this . - /// The to copy. - public MultiplierControlPoint(double startTime, MultiplierControlPoint other) - : this(startTime) - { - TimingPoint = other.TimingPoint; - DifficultyPoint = other.DifficultyPoint; - } - // ReSharper disable once ImpureMethodCallOnReadonlyValueField public int CompareTo(MultiplierControlPoint other) => StartTime.CompareTo(other?.StartTime); } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs index 3fc67e4e34..41cdd6c06f 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingRulesetContainer.cs @@ -60,6 +60,7 @@ namespace osu.Game.Rulesets.UI.Scrolling return new MultiplierControlPoint(c.Time) { + Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier, TimingPoint = lastTimingPoint, DifficultyPoint = lastDifficultyPoint }; @@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.UI.Scrolling // If we have no control points, add a default one if (DefaultControlPoints.Count == 0) - DefaultControlPoints.Add(new MultiplierControlPoint()); + DefaultControlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield)); } @@ -88,22 +89,5 @@ namespace osu.Game.Rulesets.UI.Scrolling playfield.HitObjects.AddControlPoint(controlPoint); playfield.NestedPlayfields?.OfType().ForEach(p => applySpeedAdjustment(controlPoint, p)); } - - /// - /// Generates a with the default timing change/difficulty change from the beatmap at a time. - /// - /// The time to create the control point at. - /// The default at . - public MultiplierControlPoint CreateControlPointAt(double time) - { - if (DefaultControlPoints.Count == 0) - return new MultiplierControlPoint(time); - - int index = DefaultControlPoints.BinarySearch(new MultiplierControlPoint(time)); - if (index < 0) - return new MultiplierControlPoint(time); - - return new MultiplierControlPoint(time, DefaultControlPoints[index]); - } } } From 08bd36382750a65959608230cdd51dcb84731936 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 1 Oct 2018 18:15:55 +0900 Subject: [PATCH 11/93] Adjust taiko scrolling speed --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 325beb38a5..cb927bf15a 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -194,7 +194,7 @@ namespace osu.Game.Rulesets.Taiko.UI } }); - VisibleTimeRange.Value = 6000; + VisibleTimeRange.Value = 7000; } [BackgroundDependencyLoader] From 4af885f6b1b4a28b91c6fa115e8f1718b2041c97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 1 Oct 2018 18:30:52 +0900 Subject: [PATCH 12/93] Adjust default mania speed to match stable --- osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs index 3e9c9feba1..1c9e1e4c73 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Configuration { base.InitialiseDefaults(); - Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0); + Set(ManiaSetting.ScrollTime, 2250.0, 50.0, 10000.0, 50.0); Set(ManiaSetting.ScrollDirection, ManiaScrollingDirection.Down); } From d0007c047a9d296da0cc4d47eebfdb2aac5529f3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 10:39:18 +0900 Subject: [PATCH 13/93] PlayfieldLayer -> PlayfieldAdjustmentContainer --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- .../UI/{PlayfieldLayer.cs => PlayfieldAdjustmentContainer.cs} | 4 ++-- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 +- .../UI/{PlayfieldLayer.cs => PlayfieldAdjustmentContainer.cs} | 4 ++-- .../UI/{PlayfieldLayer.cs => PlayfieldAdjustmentContainer.cs} | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) rename osu.Game.Rulesets.Catch/UI/{PlayfieldLayer.cs => PlayfieldAdjustmentContainer.cs} (92%) rename osu.Game.Rulesets.Osu/UI/{PlayfieldLayer.cs => PlayfieldAdjustmentContainer.cs} (92%) rename osu.Game.Rulesets.Taiko/UI/{PlayfieldLayer.cs => PlayfieldAdjustmentContainer.cs} (92%) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index b90b90f45a..386c8d71c7 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.UI Size = new Vector2(0.86f); // matches stable's vertical offset for catcher plate - InternalChild = new PlayfieldLayer + InternalChild = new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs similarity index 92% rename from osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs rename to osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs index d167dc59cc..ad0073ff12 100644 --- a/osu.Game.Rulesets.Catch/UI/PlayfieldLayer.cs +++ b/osu.Game.Rulesets.Catch/UI/PlayfieldAdjustmentContainer.cs @@ -7,12 +7,12 @@ using OpenTK; namespace osu.Game.Rulesets.Catch.UI { - public class PlayfieldLayer : Container + public class PlayfieldAdjustmentContainer : Container { protected override Container Content => content; private readonly Container content; - public PlayfieldLayer() + public PlayfieldAdjustmentContainer() { InternalChild = new Container { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index ad92ea15d4..d6972d55d2 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit new HitObjectCompositionTool() }; - protected override Container CreateLayerContainer() => new PlayfieldLayer { RelativeSizeAxes = Axes.Both }; + protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; public override HitObjectMask CreateMaskFor(DrawableHitObject hitObject) { diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index ae8dc7397d..47a38dccb3 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI Size = new Vector2(0.75f); - InternalChild = new PlayfieldLayer + InternalChild = new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Osu/UI/PlayfieldAdjustmentContainer.cs similarity index 92% rename from osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs rename to osu.Game.Rulesets.Osu/UI/PlayfieldAdjustmentContainer.cs index a4c84e4905..00d5692fda 100644 --- a/osu.Game.Rulesets.Osu/UI/PlayfieldLayer.cs +++ b/osu.Game.Rulesets.Osu/UI/PlayfieldAdjustmentContainer.cs @@ -7,12 +7,12 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.UI { - public class PlayfieldLayer : Container + public class PlayfieldAdjustmentContainer : Container { protected override Container Content => content; private readonly Container content; - public PlayfieldLayer() + public PlayfieldAdjustmentContainer() { InternalChild = new Container { diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldAdjustmentContainer.cs similarity index 92% rename from osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs rename to osu.Game.Rulesets.Taiko/UI/PlayfieldAdjustmentContainer.cs index c4e2f32c92..661a4e135c 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldLayer.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldAdjustmentContainer.cs @@ -6,7 +6,7 @@ using OpenTK; namespace osu.Game.Rulesets.Taiko.UI { - public class PlayfieldLayer : Container + public class PlayfieldAdjustmentContainer : Container { private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; private const float default_aspect = 16f / 9f; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 82ab327993..c6389e3f28 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Taiko.UI { Direction.Value = ScrollingDirection.Left; - InternalChild = new PlayfieldLayer + InternalChild = new PlayfieldAdjustmentContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, From cb1703c6e2181cd2ada72d90dba67c874d068887 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 11:19:01 +0900 Subject: [PATCH 14/93] Fix colours with alpha components not being parsed --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 3 ++- .../Resources/Soleily - Renatus (Gamu) [Insane].osu | 1 + osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 13 +++++++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index d3351f86f8..af63a39662 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -165,7 +165,7 @@ namespace osu.Game.Tests.Beatmaps.Formats } [Test] - public void TestDecodeBeatmapColors() + public void TestDecodeBeatmapColours() { var decoder = new LegacySkinDecoder(); using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) @@ -181,6 +181,7 @@ namespace osu.Game.Tests.Beatmaps.Formats new Color4(128, 255, 128, 255), new Color4(255, 187, 255, 255), new Color4(255, 177, 140, 255), + new Color4(100, 100, 100, 100), }; Assert.AreEqual(expectedColors.Length, comboColors.Count); for (int i = 0; i < expectedColors.Length; i++) diff --git a/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu b/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu index 3e44dc0af8..67570ad21b 100644 --- a/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu +++ b/osu.Game.Tests/Resources/Soleily - Renatus (Gamu) [Insane].osu @@ -101,6 +101,7 @@ Combo3 : 128,255,255 Combo4 : 128,255,128 Combo5 : 255,187,255 Combo6 : 255,177,140 +Combo7 : 100,100,100,100 [HitObjects] 192,168,956,6,0,P|184:128|200:80,1,90,4|0,1:2|0:0,0:0:0:0: diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index e9f37e583b..7ac88dfc5b 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -85,13 +85,18 @@ namespace osu.Game.Beatmaps.Formats string[] split = pair.Value.Split(','); - if (split.Length != 3) - throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B): {pair.Value}"); + if (split.Length != 3 && split.Length != 4) + throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B or R,G,B,A): {pair.Value}"); - if (!byte.TryParse(split[0], out var r) || !byte.TryParse(split[1], out var g) || !byte.TryParse(split[2], out var b)) + byte a = 255; + + if (!byte.TryParse(split[0], out var r) || !byte.TryParse(split[1], out var g) || !byte.TryParse(split[2], out var b) + || split.Length == 4 && !byte.TryParse(split[3], out a)) + { throw new InvalidOperationException(@"Color must be specified with 8-bit integer components"); + } - Color4 colour = new Color4(r, g, b, 255); + Color4 colour = new Color4(r, g, b, a); if (isCombo) { From 40c17cfa5a504577e1c1c119b4970f76d880c67c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 11:55:59 +0900 Subject: [PATCH 15/93] Remove ugly if-statement --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 7ac88dfc5b..222f3589dc 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -88,16 +88,17 @@ namespace osu.Game.Beatmaps.Formats if (split.Length != 3 && split.Length != 4) throw new InvalidOperationException($@"Color specified in incorrect format (should be R,G,B or R,G,B,A): {pair.Value}"); - byte a = 255; + Color4 colour; - if (!byte.TryParse(split[0], out var r) || !byte.TryParse(split[1], out var g) || !byte.TryParse(split[2], out var b) - || split.Length == 4 && !byte.TryParse(split[3], out a)) + try + { + colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), split.Length == 4 ? byte.Parse(split[3]) : 255); + } + catch (Exception e) { throw new InvalidOperationException(@"Color must be specified with 8-bit integer components"); } - Color4 colour = new Color4(r, g, b, a); - if (isCombo) { if (!(output is IHasComboColours tHasComboColours)) return; From 794501cc5a5297dff081c69eaf87e4a3e1a9ce2b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 12:06:24 +0900 Subject: [PATCH 16/93] Fix incorrect result of ternary --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 222f3589dc..a9e1e4c55d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -92,7 +92,7 @@ namespace osu.Game.Beatmaps.Formats try { - colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), split.Length == 4 ? byte.Parse(split[3]) : 255); + colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), split.Length == 4 ? byte.Parse(split[3]) : (byte)255); } catch (Exception e) { From 42664f1c190a065e4f11b3afea5f408ece96d739 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 15:45:45 +0900 Subject: [PATCH 17/93] Make SliderBody use the new SmoothPath --- .../Objects/Drawables/Pieces/SliderBody.cs | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs index f3924ec43b..f4ccf673e9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBody.cs @@ -8,26 +8,23 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; -using osu.Framework.Graphics.Textures; using OpenTK.Graphics.ES30; using OpenTK.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Rulesets.Objects.Types; using OpenTK; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { public class SliderBody : Container, ISliderProgress { - private readonly Path path; + private readonly SliderPath path; private readonly BufferedContainer container; public float PathWidth { - get { return path.PathWidth; } - set { path.PathWidth = value; } + get => path.PathWidth; + set => path.PathWidth = value; } /// @@ -43,48 +40,40 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces public double? SnakedStart { get; private set; } public double? SnakedEnd { get; private set; } - private Color4 accentColour = Color4.White; - /// /// Used to colour the path. /// public Color4 AccentColour { - get { return accentColour; } + get => path.AccentColour; set { - if (accentColour == value) + if (path.AccentColour == value) return; - accentColour = value; + path.AccentColour = value; - if (LoadState >= LoadState.Ready) - reloadTexture(); + container.ForceRedraw(); } } - private Color4 borderColour = Color4.White; - /// /// Used to colour the path border. /// public new Color4 BorderColour { - get { return borderColour; } + get => path.BorderColour; set { - if (borderColour == value) + if (path.BorderColour == value) return; - borderColour = value; + path.BorderColour = value; - if (LoadState >= LoadState.Ready) - reloadTexture(); + container.ForceRedraw(); } } public Quad PathDrawQuad => container.ScreenSpaceDrawQuad; - private int textureWidth => (int)PathWidth * 2; - private Vector2 topLeftOffset; private readonly Slider slider; @@ -101,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces CacheDrawnFrameBuffer = true, Children = new Drawable[] { - path = new Path + path = new SliderPath { Blending = BlendingMode.None, }, @@ -134,46 +123,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces [BackgroundDependencyLoader] private void load() { - reloadTexture(); computeSize(); } - private void reloadTexture() - { - var texture = new Texture(textureWidth, 1); - - //initialise background - var raw = new Image(textureWidth, 1); - - const float aa_portion = 0.02f; - const float border_portion = 0.128f; - const float gradient_portion = 1 - border_portion; - - const float opacity_at_centre = 0.3f; - const float opacity_at_edge = 0.8f; - - for (int i = 0; i < textureWidth; i++) - { - float progress = (float)i / (textureWidth - 1); - - if (progress <= border_portion) - { - raw[i, 0] = new Rgba32(BorderColour.R, BorderColour.G, BorderColour.B, Math.Min(progress / aa_portion, 1) * BorderColour.A); - } - else - { - progress -= border_portion; - raw[i, 0] = new Rgba32(AccentColour.R, AccentColour.G, AccentColour.B, - (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * progress / gradient_portion) * AccentColour.A); - } - } - - texture.SetData(new TextureUpload(raw)); - path.Texture = texture; - - container.ForceRedraw(); - } - private void computeSize() { // Generate the entire curve @@ -226,5 +178,53 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces SetRange(start, end); } + + private class SliderPath : SmoothPath + { + private const float border_portion = 0.128f; + private const float gradient_portion = 1 - border_portion; + + private const float opacity_at_centre = 0.3f; + private const float opacity_at_edge = 0.8f; + + private Color4 borderColour = Color4.White; + + public Color4 BorderColour + { + get => borderColour; + set + { + if (borderColour == value) + return; + borderColour = value; + + InvalidateTexture(); + } + } + + private Color4 accentColour = Color4.White; + + public Color4 AccentColour + { + get => accentColour; + set + { + if (accentColour == value) + return; + accentColour = value; + + InvalidateTexture(); + } + } + + protected override Color4 ColourAt(float position) + { + if (position <= border_portion) + return BorderColour; + + position -= border_portion; + return new Color4(AccentColour.R, AccentColour.G, AccentColour.B, (opacity_at_edge - (opacity_at_edge - opacity_at_centre) * position / gradient_portion) * AccentColour.A); + } + } } } From f7ebd063c39f66a0dd24cc61ad875fddd26f63e6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 5 Oct 2018 15:45:53 +0900 Subject: [PATCH 18/93] Make user profile graph use a smooth path --- osu.Game/Graphics/UserInterface/LineGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index 3cb2446acc..ff2c4cf7cd 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.UserInterface { Masking = true, RelativeSizeAxes = Axes.Both, - Child = path = new Path { RelativeSizeAxes = Axes.Both, PathWidth = 1 } + Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathWidth = 1 } }); } From 8264dd49de638342b182996e7c6761d8831e46ca Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Fri, 5 Oct 2018 07:13:18 -0400 Subject: [PATCH 19/93] Update bindable only if enabled --- osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index 7470dd0cd5..c698e9eeb0 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -76,7 +76,10 @@ namespace osu.Game.Overlays.Toolbar modeButtons.Add(new ToolbarRulesetButton { Ruleset = r, - Action = delegate { ruleset.Value = r; } + Action = delegate + { + if (!ruleset.Disabled) ruleset.Value = r; + } }); } From 8b27741cb0fb83a05766f14aefae59490e3a26b2 Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Fri, 5 Oct 2018 11:37:44 -0400 Subject: [PATCH 20/93] Do not propagate positional input to subtree --- osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index c698e9eeb0..c5b583f390 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -76,10 +76,7 @@ namespace osu.Game.Overlays.Toolbar modeButtons.Add(new ToolbarRulesetButton { Ruleset = r, - Action = delegate - { - if (!ruleset.Disabled) ruleset.Value = r; - } + Action = delegate { ruleset.Value = r; } }); } @@ -108,6 +105,8 @@ namespace osu.Game.Overlays.Toolbar public override bool HandleNonPositionalInput => !ruleset.Disabled && base.HandleNonPositionalInput; public override bool HandlePositionalInput => !ruleset.Disabled && base.HandlePositionalInput; + public override bool PropagatePositionalInputSubTree => false; + private void disabledChanged(bool isDisabled) => this.FadeColour(isDisabled ? Color4.Gray : Color4.White, 300); protected override void Update() From ca9cbf1aead025c873fca0675030ec149cca6cd0 Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Sat, 6 Oct 2018 07:51:56 -0400 Subject: [PATCH 21/93] Fix rulsets being completed unselectable --- osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index c5b583f390..138f3ffc3f 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Toolbar public override bool HandleNonPositionalInput => !ruleset.Disabled && base.HandleNonPositionalInput; public override bool HandlePositionalInput => !ruleset.Disabled && base.HandlePositionalInput; - public override bool PropagatePositionalInputSubTree => false; + public override bool PropagatePositionalInputSubTree => !ruleset.Disabled; private void disabledChanged(bool isDisabled) => this.FadeColour(isDisabled ? Color4.Gray : Color4.White, 300); From 6b236e3f2a097279f57477f08ef0c486320ac33a Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Sat, 6 Oct 2018 08:06:26 -0400 Subject: [PATCH 22/93] Handle non positional input only when opened --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 26caf09b1b..41bdb78a4d 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -51,6 +51,8 @@ namespace osu.Game.Graphics.UserInterface #region OsuDropdownMenu protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour { + public override bool HandleNonPositionalInput => this.State == MenuState.Open; + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring public OsuDropdownMenu() { From aedb6e3bb77c331087632ce34c93c53c0cbfe600 Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Sat, 6 Oct 2018 08:12:29 -0400 Subject: [PATCH 23/93] Remove dedundant this qualifier --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 41bdb78a4d..04a7cb64d3 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -51,7 +51,7 @@ namespace osu.Game.Graphics.UserInterface #region OsuDropdownMenu protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour { - public override bool HandleNonPositionalInput => this.State == MenuState.Open; + public override bool HandleNonPositionalInput => State == MenuState.Open; // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring public OsuDropdownMenu() From db443babb6e9281525c65cda4cf71db065eddbb0 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sun, 7 Oct 2018 19:15:42 +0200 Subject: [PATCH 24/93] Fix database entries using platform-specific path separator --- osu.Game/Database/ArchiveModelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 723bb90e7e..3686b702c4 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -404,7 +404,7 @@ namespace osu.Game.Database using (Stream s = reader.GetStream(file)) fileInfos.Add(new TFileModel { - Filename = FileSafety.PathSanitise(file), + Filename = FileSafety.PathStandardise(file), FileInfo = files.Add(s) }); From 97f86193018b9e15bac824a1b737580ab643ab83 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Sun, 7 Oct 2018 21:07:30 +0200 Subject: [PATCH 25/93] Add database migration for standardizing paths --- ...0181007180454_StandardizePaths.Designer.cs | 380 ++++++++++++++++++ .../20181007180454_StandardizePaths.cs | 42 ++ .../Migrations/OsuDbContextModelSnapshot.cs | 2 +- 3 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs create mode 100644 osu.Game/Migrations/20181007180454_StandardizePaths.cs diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs new file mode 100644 index 0000000000..b387a45ecf --- /dev/null +++ b/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs @@ -0,0 +1,380 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using osu.Game.Database; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20181007180454_StandardizePaths")] + partial class StandardizePaths + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("DistanceSpacing"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("Status"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash"); + + b.HasIndex("MD5Hash"); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.Property("Status"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntKey") + .HasColumnName("Key"); + + b.Property("RulesetID"); + + b.Property("StringValue") + .HasColumnName("Value"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.Property("ShortName"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.HasIndex("ShortName") + .IsUnique(); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("SkinInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("SkinInfoID"); + + b.ToTable("SkinFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Creator"); + + b.Property("DeletePending"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.ToTable("SkinInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Files") + .HasForeignKey("SkinInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.cs new file mode 100644 index 0000000000..08b34507ce --- /dev/null +++ b/osu.Game/Migrations/20181007180454_StandardizePaths.cs @@ -0,0 +1,42 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using System.IO; + +namespace osu.Game.Migrations +{ + public partial class StandardizePaths : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + string sanitized = Path.DirectorySeparatorChar.ToString(); + string standardized = "/"; + + // If we are not on Windows, no changes are needed. + if (string.Equals(standardized, sanitized, StringComparison.Ordinal)) + return; + + // Escaping \ does not seem to be needed. + migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{sanitized}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{sanitized}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `BackgroundFile` = REPLACE(`BackgroundFile`, '{sanitized}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapSetFileInfo` SET `Filename` = REPLACE(`Filename`, '{sanitized}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `SkinFileInfo` SET `Filename` = REPLACE(`Filename`, '{sanitized}', '{standardized}')"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + string sanitized = Path.DirectorySeparatorChar.ToString(); + string standardized = "/"; + + // If we are not on Windows, no changes are needed. + if (string.Equals(standardized, sanitized, StringComparison.Ordinal)) + return; + + migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{standardized}', '{sanitized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{standardized}', '{sanitized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `BackgroundFile` = REPLACE(`BackgroundFile`, '{standardized}', '{sanitized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapSetFileInfo` SET `Filename` = REPLACE(`Filename`, '{standardized}', '{sanitized}')"); + migrationBuilder.Sql($"UPDATE `SkinFileInfo` SET `Filename` = REPLACE(`Filename`, '{standardized}', '{sanitized}')"); + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index fde5c9fd82..663676a6d3 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -14,7 +14,7 @@ namespace osu.Game.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "2.1.2-rtm-30932"); + .HasAnnotation("ProductVersion", "2.1.3-rtm-32065"); modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => { From da976000763e6bcf7975714fa971a08b48777bed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 16:46:58 +0900 Subject: [PATCH 26/93] Fix inaccurate section lengths for first hitobject --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 5e91ed7a97..028e3acc57 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double sectionLength = section_length * timeRate; // The first object doesn't generate a strain, so we begin with an incremented section end - double currentSectionEnd = 2 * sectionLength; + double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength; foreach (OsuDifficultyHitObject h in difficultyBeatmap) { From 61e7ada977c3567463af8d48a38f7145c2605046 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 17:36:06 +0900 Subject: [PATCH 27/93] Use ints + fix position calculation --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 29de23406b..7f293fd099 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing var computeVertex = new Action(t => { // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPositionAt(t) - slider.LazyEndPosition.Value; + var diff = slider.StackedPositionAt(((int)t - (int)slider.StartTime) / (float)(int)slider.Duration) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From 1ad5090ad68b52da6a49114c5f5187e200bc05cc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 17:37:33 +0900 Subject: [PATCH 28/93] Separate travel distance from jump distance --- .../Preprocessing/OsuDifficultyHitObject.cs | 16 +++++++++++----- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 7f293fd099..2419709e41 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -21,9 +21,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing public OsuHitObject BaseObject { get; } /// - /// Normalized distance from the of the previous . + /// Normalized distance from the end position of the previous . /// - public double Distance { get; private set; } + public double JumpDistance { get; private set; } + + /// + /// Normalized distance from the start position to the end position of the previous . + /// + public double TravelDistance { get; private set; } /// /// Milliseconds elapsed since the StartTime of the previous . @@ -51,10 +56,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing private void setDistances() { // We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps. - double scalingFactor = normalized_radius / BaseObject.Radius; + float scalingFactor = normalized_radius / (float)BaseObject.Radius; if (BaseObject.Radius < 30) { - double smallCircleBonus = Math.Min(30 - BaseObject.Radius, 5) / 50; + float smallCircleBonus = Math.Min(30 - (float)BaseObject.Radius, 5) / 50; scalingFactor *= 1 + smallCircleBonus; } @@ -69,7 +74,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - Distance = (lastTravelDistance + (BaseObject.StackedPosition - lastCursorPosition).Length) * scalingFactor; + JumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; + TravelDistance = lastTravelDistance * scalingFactor; } private void setTimingValues() diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 0a45c62671..9ffdd280aa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double SkillMultiplier => 26.25; protected override double StrainDecayBase => 0.15; - protected override double StrainValueOf(OsuDifficultyHitObject current) => Math.Pow(current.Distance, 0.99) / current.DeltaTime; + protected override double StrainValueOf(OsuDifficultyHitObject current) => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.DeltaTime; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index b807f20037..501a8e8e01 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainValueOf(OsuDifficultyHitObject current) { - double distance = current.Distance; + double distance = current.TravelDistance + current.JumpDistance; double speedValue; if (distance > single_spacing_threshold) From 35f45e74dc2e5e41da3dd186e78652b329610687 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 17:39:10 +0900 Subject: [PATCH 29/93] Calculate scaled positions prior to square-rooting --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 2419709e41..b9eaf9ff04 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - JumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; + JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; TravelDistance = lastTravelDistance * scalingFactor; } From 0116db95d0363f0ac15932980a307fd7ff458b5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 18:37:30 +0900 Subject: [PATCH 30/93] Fix progress calculation --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index b9eaf9ff04..26db2e3faa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using OpenTK; @@ -93,8 +94,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => { + double progress = ((int)t - (int)slider.StartTime) / (float)(int)slider.SpanDuration; + if (progress % 2 > 1) + progress = 1 - progress % 1; + else + progress = progress % 1; + // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPositionAt(((int)t - (int)slider.StartTime) / (float)(int)slider.Duration) - slider.LazyEndPosition.Value; + var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From f8eaccddda1d1b1657127e6ae29778d909904edb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 18:37:49 +0900 Subject: [PATCH 31/93] Stable doesn't use stacked positions --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 26db2e3faa..44bec47e14 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Vector2 lastCursorPosition = lastObject.StackedPosition; + Vector2 lastCursorPosition = lastObject.Position; float lastTravelDistance = 0; var lastSlider = lastObject as Slider; @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; + JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; TravelDistance = lastTravelDistance * scalingFactor; } @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { if (slider.LazyEndPosition != null) return; - slider.LazyEndPosition = slider.StackedPosition; + slider.LazyEndPosition = slider.Position; float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => @@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing progress = progress % 1; // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; + var diff = slider.Position + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From b7499fa95627d054e9a3a881420a92808cf12ebe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 11:34:38 +0900 Subject: [PATCH 32/93] Allow TimingControlPoint to be overridden --- .../Beatmaps/ControlPoints/TimingControlPoint.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index eb60133fed..81eddaa43a 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -16,7 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The beat length at this control point. /// - public double BeatLength + public virtual double BeatLength { get => beatLength; set => beatLength = MathHelper.Clamp(value, 6, 60000); diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 181d17932d..5b5bc5d936 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -318,12 +318,12 @@ namespace osu.Game.Beatmaps.Formats if (timingChange) { - handleTimingControlPoint(new TimingControlPoint - { - Time = time, - BeatLength = beatLength, - TimeSignature = timeSignature - }); + var controlPoint = CreateTimingControlPoint(); + controlPoint.Time = time; + controlPoint.BeatLength = beatLength; + controlPoint.TimeSignature = timeSignature; + + handleTimingControlPoint(controlPoint); } handleDifficultyControlPoint(new DifficultyControlPoint @@ -418,6 +418,8 @@ namespace osu.Game.Beatmaps.Formats private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0); + protected virtual TimingControlPoint CreateTimingControlPoint() => new TimingControlPoint(); + [Flags] internal enum EffectFlags { From 9facf707be57018b816417d6a8677f5719d87c35 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 11:49:24 +0900 Subject: [PATCH 33/93] Add diffcalc beatmap decoder --- .../Preprocessing/OsuDifficultyHitObject.cs | 1 - ...egacyDifficultyCalculatorBeatmapDecoder.cs | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 44bec47e14..448dc140a3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using OpenTK; diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs new file mode 100644 index 0000000000..61efd329c0 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Beatmaps.Formats +{ + /// + /// A built for difficulty calculation of legacy s + /// + /// To use this, the decoder must be registered by the application through . + /// Doing so will override any existing decoders. + /// + /// + public class LegacyDifficultyCalculatorBeatmapDecoder : LegacyBeatmapDecoder + { + public LegacyDifficultyCalculatorBeatmapDecoder(int version = LATEST_VERSION) + : base(version) + { + } + + public new static void Register() + { + AddDecoder(@"osu file format v", m => new LegacyDifficultyCalculatorBeatmapDecoder(int.Parse(m.Split('v').Last()))); + } + + protected override TimingControlPoint CreateTimingControlPoint() + => new LegacyDifficultyCalculatorControlPoint(); + + private class LegacyDifficultyCalculatorControlPoint : TimingControlPoint + { + public override double BeatLength { get; set; } = 1000; + } + } +} From 0a3be0d253c076bfda1a95ebb26854808be30293 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 12:03:47 +0900 Subject: [PATCH 34/93] Adjust comments slightly --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 448dc140a3..a118d95ff7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -21,12 +21,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing public OsuHitObject BaseObject { get; } /// - /// Normalized distance from the end position of the previous . + /// Normalized distance from the end position of the previous to the start position of this . /// public double JumpDistance { get; private set; } /// - /// Normalized distance from the start position to the end position of the previous . + /// Normalized distance between the start and end position of the previous . /// public double TravelDistance { get; private set; } From a171ed350006fa6f918d527dbefccddf920c13c7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Oct 2018 16:12:20 +0900 Subject: [PATCH 35/93] Fix joined channels not appearing as joined in the channel list --- osu.Game/Overlays/ChatOverlay.cs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index eeadac8e8c..ff2ff9af14 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -291,7 +291,7 @@ namespace osu.Game.Overlays messageRequest?.Cancel(); ListChannelsRequest req = new ListChannelsRequest(); - req.Success += delegate (List channels) + req.Success += delegate(List channels) { AvailableChannels = channels; @@ -323,10 +323,7 @@ namespace osu.Game.Overlays protected Channel CurrentChannel { - get - { - return currentChannel; - } + get { return currentChannel; } set { @@ -445,13 +442,7 @@ namespace osu.Game.Overlays if (updates?.Presence != null) { foreach (var channel in updates.Presence) - { - if (careChannels.Find(c => c.Id == channel.Id) == null) - { - channel.Joined.Value = true; - addChannel(channel); - } - } + addChannel(AvailableChannels.Find(c => c.Id == channel.Id)); foreach (var group in updates.Messages.GroupBy(m => m.ChannelId)) careChannels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); @@ -462,10 +453,7 @@ namespace osu.Game.Overlays fetchReq = null; }; - fetchReq.Failure += delegate - { - fetchReq = null; - }; + fetchReq.Failure += delegate { fetchReq = null; }; api.Queue(fetchReq); } From ccb6723711351e66a509f5c1ce6392a8fcdb27e4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 16:50:29 +0900 Subject: [PATCH 36/93] Debounce music controller seeks --- osu.Game/Overlays/MusicController.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index e3dc504e4d..b32fd265cb 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -196,10 +196,16 @@ namespace osu.Game.Overlays playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint); } + private ScheduledDelegate seekDelegate; + private void attemptSeek(double progress) { - if (!beatmap.Disabled) - current?.Track.Seek(progress); + seekDelegate?.Cancel(); + seekDelegate = Schedule(() => + { + if (!beatmap.Disabled) + current?.Track.Seek(progress); + }); } private void playlistOrderChanged(BeatmapSetInfo beatmapSetInfo, int index) From 6d24bde72ba8cd3ac6d932d2de8b685a21689d9b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 17:39:27 +0900 Subject: [PATCH 37/93] Fix beatmap details not displaying --- osu.Game/Screens/Select/BeatmapDetails.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index f1bd2b945f..f7b955941d 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -327,11 +327,6 @@ namespace osu.Game.Screens.Select TextSize = 14, }, }, - textFlow = new OsuTextFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, }, }; } @@ -350,6 +345,8 @@ namespace osu.Game.Screens.Select } } + public override bool IsPresent => base.IsPresent || textFlow == null; // Visibility is updated in the LoadComponentAsync callback + private void setTextAsync(string text) { LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14) From ae79c3832e720eef2b26cd9efeacf1081e93415a Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Tue, 9 Oct 2018 11:05:15 -0400 Subject: [PATCH 38/93] Add base. for safety --- osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index 138f3ffc3f..fa35e53531 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.Toolbar public override bool HandleNonPositionalInput => !ruleset.Disabled && base.HandleNonPositionalInput; public override bool HandlePositionalInput => !ruleset.Disabled && base.HandlePositionalInput; - public override bool PropagatePositionalInputSubTree => !ruleset.Disabled; + public override bool PropagatePositionalInputSubTree => !ruleset.Disabled && base.PropagatePositionalInputSubTree; private void disabledChanged(bool isDisabled) => this.FadeColour(isDisabled ? Color4.Gray : Color4.White, 300); From b35f88b8ba460be6d7d4a36e3c5761a1a2938bef Mon Sep 17 00:00:00 2001 From: HoLLy Date: Tue, 9 Oct 2018 17:49:18 +0200 Subject: [PATCH 39/93] Standardize AudioFile and BackgroundImage paths --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 181d17932d..3030fcb9da 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -5,6 +5,7 @@ using System; using System.Globalization; using System.IO; using System.Linq; +using osu.Framework.IO.File; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Beatmaps.ControlPoints; @@ -100,7 +101,7 @@ namespace osu.Game.Beatmaps.Formats switch (pair.Key) { case @"AudioFilename": - metadata.AudioFile = pair.Value; + metadata.AudioFile = FileSafety.PathStandardise(pair.Value); break; case @"AudioLeadIn": beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value); @@ -256,7 +257,7 @@ namespace osu.Game.Beatmaps.Formats { case EventType.Background: string filename = split[2].Trim('"'); - beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + beatmap.BeatmapInfo.Metadata.BackgroundFile = FileSafety.PathStandardise(filename); break; case EventType.Break: var breakEvent = new BreakPeriod From d6784c818e02d02c72a86ee3bb5071009b18be63 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 11:49:54 +0900 Subject: [PATCH 40/93] Fix jump/travel distances in some scenarios --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index a118d95ff7..0400f080d9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -74,8 +74,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; - TravelDistance = lastTravelDistance * scalingFactor; + // Don't need to jump to reach spinners + if (!(BaseObject is Spinner)) + JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; + + // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also sliders! + if (BaseObject is Slider) + TravelDistance = lastTravelDistance * scalingFactor; } private void setTimingValues() From 1125075b374ea717111998ab4f0f20a357baf98d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 13:02:27 +0900 Subject: [PATCH 41/93] Use list with post-sort for nested hitobjects --- osu.Game/Rulesets/Objects/HitObject.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index beb9620f78..80a3677b12 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Objects /// public HitWindows HitWindows { get; set; } - private readonly Lazy> nestedHitObjects = new Lazy>(() => new SortedList((h1, h2) => h1.StartTime.CompareTo(h2.StartTime))); + private readonly Lazy> nestedHitObjects = new Lazy>(() => new List()); [JsonIgnore] public IReadOnlyList NestedHitObjects => nestedHitObjects.Value; @@ -79,6 +79,8 @@ namespace osu.Game.Rulesets.Objects if (nestedHitObjects.IsValueCreated) { + nestedHitObjects.Value.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); + nestedHitObjects.Value.ForEach(h => { h.HitWindows = HitWindows; From 417ebaeb857a50f65f484ca5c6d424539046f3b0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 13:03:18 +0900 Subject: [PATCH 42/93] Reduce hitobject size by removing lazy --- osu.Game/Rulesets/Objects/HitObject.cs | 27 ++++++++++---------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 80a3677b12..e52d6b416f 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -1,11 +1,8 @@ // 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 Newtonsoft.Json; -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Lists; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -58,10 +55,10 @@ namespace osu.Game.Rulesets.Objects /// public HitWindows HitWindows { get; set; } - private readonly Lazy> nestedHitObjects = new Lazy>(() => new List()); + private readonly List nestedHitObjects = new List(); [JsonIgnore] - public IReadOnlyList NestedHitObjects => nestedHitObjects.Value; + public IReadOnlyList NestedHitObjects => nestedHitObjects; /// /// Applies default values to this HitObject. @@ -72,21 +69,17 @@ namespace osu.Game.Rulesets.Objects { ApplyDefaultsToSelf(controlPointInfo, difficulty); - if (nestedHitObjects.IsValueCreated) - nestedHitObjects.Value.Clear(); + nestedHitObjects.Clear(); CreateNestedHitObjects(); - if (nestedHitObjects.IsValueCreated) - { - nestedHitObjects.Value.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); + nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); - nestedHitObjects.Value.ForEach(h => - { - h.HitWindows = HitWindows; - h.ApplyDefaults(controlPointInfo, difficulty); - }); - } + nestedHitObjects.ForEach(h => + { + h.HitWindows = HitWindows; + h.ApplyDefaults(controlPointInfo, difficulty); + }); } protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) @@ -106,7 +99,7 @@ namespace osu.Game.Rulesets.Objects { } - protected void AddNested(HitObject hitObject) => nestedHitObjects.Value.Add(hitObject); + protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject); /// /// Creates the that represents the scoring information for this . From f53bb81723372ab9bb462b616ecdb89e73058b4c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 14:58:29 +0900 Subject: [PATCH 43/93] Remove unnecessary lambda allocation --- osu.Game/Rulesets/Objects/HitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index e52d6b416f..67a3db7a00 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -75,11 +75,11 @@ namespace osu.Game.Rulesets.Objects nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); - nestedHitObjects.ForEach(h => + foreach (var h in nestedHitObjects) { h.HitWindows = HitWindows; h.ApplyDefaults(controlPointInfo, difficulty); - }); + } } protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) From 03a95113994fa92d8a296370c373acc0cad65cd7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 18:08:46 +0900 Subject: [PATCH 44/93] Apparently stable does use stacking --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 0400f080d9..fd36e85f26 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Vector2 lastCursorPosition = lastObject.Position; + Vector2 lastCursorPosition = lastObject.StackedPosition; float lastTravelDistance = 0; var lastSlider = lastObject as Slider; @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) - JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; + JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also sliders! if (BaseObject is Slider) @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing progress = progress % 1; // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.Position + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; + var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From d8f77feddd705e9fc986b4c4ec3b0b3c4472f273 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 18:52:57 +0900 Subject: [PATCH 45/93] Fix using the wrong slider's travel distance --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index fd36e85f26..1c5b28f407 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -64,23 +64,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing } Vector2 lastCursorPosition = lastObject.StackedPosition; - float lastTravelDistance = 0; var lastSlider = lastObject as Slider; if (lastSlider != null) { computeSliderCursorPosition(lastSlider); lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition; - lastTravelDistance = lastSlider.LazyTravelDistance; } // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; - // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also sliders! + // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also a slider! if (BaseObject is Slider) - TravelDistance = lastTravelDistance * scalingFactor; + TravelDistance = (lastSlider?.LazyTravelDistance ?? 0) * scalingFactor; } private void setTimingValues() From 4e37b5c4a7878b11905efd2c4be80ba5e10f33f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 18:53:54 +0900 Subject: [PATCH 46/93] 50ms cap shouldn't be included in the strain decay --- .../Preprocessing/OsuDifficultyHitObject.cs | 11 +++++++++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 3 ++- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 1c5b28f407..4905c007b9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -35,6 +35,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double DeltaTime { get; private set; } + /// + /// Milliseconds elapsed since the start time of the previous , with a minimum of 50ms. + /// + public double StrainTime { get; private set; } + private readonly OsuHitObject lastObject; private readonly double timeRate; @@ -83,8 +88,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing private void setTimingValues() { - // Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure. - DeltaTime = Math.Max(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate); + DeltaTime = (BaseObject.StartTime - lastObject.StartTime) / timeRate; + + // Every strain interval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure + StrainTime = Math.Max(50, DeltaTime); } private void computeSliderCursorPosition(Slider slider) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 9ffdd280aa..f11b6d66f6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double SkillMultiplier => 26.25; protected override double StrainDecayBase => 0.15; - protected override double StrainValueOf(OsuDifficultyHitObject current) => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.DeltaTime; + protected override double StrainValueOf(OsuDifficultyHitObject current) + => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 501a8e8e01..1cde03624b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills else speedValue = 0.95; - return speedValue / current.DeltaTime; + return speedValue / current.StrainTime; } } } From d28b9860ff5e47ea467f871405626f619b881569 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Oct 2018 19:26:35 +0900 Subject: [PATCH 47/93] Don't use "beatmapset" terminology --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f17496e200..b4f552ce93 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -204,7 +204,7 @@ namespace osu.Game.Screens.Select Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2); Footer.AddButton(@"options", colours.Blue, BeatmapOptions, Key.F3); - BeatmapOptions.AddButton(@"Delete", @"beatmapset", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); + BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.fa_trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo), Key.Number4, float.MaxValue); } if (this.beatmaps == null) From ed0dcb2e7333e47d5cf66d4cdd27cd48d4300292 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Oct 2018 19:41:40 +0900 Subject: [PATCH 48/93] Add comment explaining why --- osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs b/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs index d871cdd322..fca04ca513 100644 --- a/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs +++ b/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObject.cs @@ -13,6 +13,7 @@ namespace osu.Game.Rulesets.Mods { /// /// Applies this to a list of s. + /// This will only be invoked with top-level s. Access if adjusting nested objects is necessary. /// /// The list of s to apply to. void ApplyToDrawableHitObjects(IEnumerable drawables); From f675c939356a9140c7a4e77b7adbbd602f0e986e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 21:37:02 +0900 Subject: [PATCH 49/93] Stably-sort hitobjects --- .../Difficulty/Preprocessing/OsuDifficultyBeatmap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs index 4443a0e66b..24d4677981 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; +using System.Linq; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing @@ -23,8 +24,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { // Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases. // This should probably happen before the objects reach the difficulty calculator. - objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime)); - difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate); + difficultyObjects = createDifficultyObjectEnumerator(objects.OrderBy(h => h.StartTime).ToList(), timeRate); } /// From 7d20efed2c9318b5bd7e1391902714438085a206 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 13:53:29 +0900 Subject: [PATCH 50/93] Fix missing stack position --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 4905c007b9..ccfcc1ef25 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { if (slider.LazyEndPosition != null) return; - slider.LazyEndPosition = slider.Position; + slider.LazyEndPosition = slider.StackedPosition; float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => From 0c4403ef16b17a71208537321b4ed6fd80c3a975 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 13:53:49 +0900 Subject: [PATCH 51/93] Don't apply version offset during diff calc --- .../Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index 61efd329c0..13a71aac3d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -18,6 +18,7 @@ namespace osu.Game.Beatmaps.Formats public LegacyDifficultyCalculatorBeatmapDecoder(int version = LATEST_VERSION) : base(version) { + ApplyOffsets = false; } public new static void Register() From 83fd251c7b1f4d6f2ba4a31f551fc0548e81f4b0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 17:44:25 +0900 Subject: [PATCH 52/93] Pass sub-controlpoints as span slices --- .../TestCaseAutoJuiceStream.cs | 3 +- .../Objects/JuiceStream.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs | 14 ++--- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 6 +-- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- .../Visual/TestCaseHitObjectComposer.cs | 2 +- osu.Game.props | 2 +- .../Rulesets/Objects/BezierApproximator.cs | 9 ++-- .../Rulesets/Objects/CatmullApproximator.cs | 16 +++--- .../Objects/CircularArcApproximator.cs | 22 ++++---- .../Legacy/Catch/ConvertHitObjectParser.cs | 2 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 24 ++++++--- .../Rulesets/Objects/Legacy/ConvertSlider.cs | 2 +- .../Legacy/Mania/ConvertHitObjectParser.cs | 2 +- .../Legacy/Osu/ConvertHitObjectParser.cs | 2 +- .../Legacy/Taiko/ConvertHitObjectParser.cs | 2 +- osu.Game/Rulesets/Objects/SliderCurve.cs | 51 ++++++++++++------- osu.Game/Rulesets/Objects/Types/IHasCurve.cs | 3 +- 18 files changed, 93 insertions(+), 73 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs index 34e07170bd..5e68acde94 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; @@ -38,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests beatmap.HitObjects.Add(new JuiceStream { X = 0.5f - width / 2, - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(width * CatchPlayfield.BASE_WIDTH, 0) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 0344189af5..82e32d24d2 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Catch.Objects public SliderCurve Curve { get; } = new SliderCurve(); - public List ControlPoints + public Vector2[] ControlPoints { get { return Curve.ControlPoints; } set { Curve.ControlPoints = value; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs index 3f9464a98f..300ac16155 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(239, 176), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(154, 28), @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-(distance / 2), 0), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(distance, 0), @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(200, 200), @@ -184,7 +184,7 @@ namespace osu.Game.Rulesets.Osu.Tests CurveType = CurveType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(150, 75), @@ -210,7 +210,7 @@ namespace osu.Game.Rulesets.Osu.Tests CurveType = CurveType.Bezier, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(150, 75), @@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Osu.Tests CurveType = CurveType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(0, 0), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(-200, 0), @@ -265,7 +265,7 @@ namespace osu.Game.Rulesets.Osu.Tests StartTime = Time.Current + 1000, Position = new Vector2(-100, 0), CurveType = CurveType.Catmull, - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(50, -50), diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 7a30e6b134..1b3725a15e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mods; @@ -33,8 +32,9 @@ namespace osu.Game.Rulesets.Osu.Mods slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - var newControlPoints = new List(); - slider.ControlPoints.ForEach(c => newControlPoints.Add(new Vector2(c.X, -c.Y))); + var newControlPoints = new Vector2[slider.ControlPoints.Length]; + for (int i = 0; i < slider.ControlPoints.Length; i++) + newControlPoints[i] = new Vector2(slider.ControlPoints[i].X, -slider.ControlPoints[i].Y); slider.ControlPoints = newControlPoints; slider.Curve?.Calculate(); // Recalculate the slider curve diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 7a0dcc77a6..c284335c98 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects public SliderCurve Curve { get; } = new SliderCurve(); - public List ControlPoints + public Vector2[] ControlPoints { get { return Curve.ControlPoints; } set { Curve.ControlPoints = value; } diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 5df371dd09..a2bc28bc3c 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual new Slider { Position = new Vector2(128, 256), - ControlPoints = new List + ControlPoints = new[] { Vector2.Zero, new Vector2(216, 0), diff --git a/osu.Game.props b/osu.Game.props index ec859e64a5..4bcac479a0 100644 --- a/osu.Game.props +++ b/osu.Game.props @@ -1,7 +1,7 @@ - 7 + 7.2 ..\app.manifest diff --git a/osu.Game/Rulesets/Objects/BezierApproximator.cs b/osu.Game/Rulesets/Objects/BezierApproximator.cs index 6094934510..a1803e32f7 100644 --- a/osu.Game/Rulesets/Objects/BezierApproximator.cs +++ b/osu.Game/Rulesets/Objects/BezierApproximator.cs @@ -1,25 +1,26 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public class BezierApproximator + public readonly ref struct BezierApproximator { private readonly int count; - private readonly List controlPoints; + private readonly ReadOnlySpan controlPoints; private readonly Vector2[] subdivisionBuffer1; private readonly Vector2[] subdivisionBuffer2; private const float tolerance = 0.25f; private const float tolerance_sq = tolerance * tolerance; - public BezierApproximator(List controlPoints) + public BezierApproximator(ReadOnlySpan controlPoints) { this.controlPoints = controlPoints; - count = controlPoints.Count; + count = controlPoints.Length; subdivisionBuffer1 = new Vector2[count]; subdivisionBuffer2 = new Vector2[count * 2 - 1]; diff --git a/osu.Game/Rulesets/Objects/CatmullApproximator.cs b/osu.Game/Rulesets/Objects/CatmullApproximator.cs index fabb55e8f6..78f8e471f3 100644 --- a/osu.Game/Rulesets/Objects/CatmullApproximator.cs +++ b/osu.Game/Rulesets/Objects/CatmullApproximator.cs @@ -1,40 +1,40 @@ // 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 OpenTK; namespace osu.Game.Rulesets.Objects { - public class CatmullApproximator + public readonly ref struct CatmullApproximator { /// /// The amount of pieces to calculate for each controlpoint quadruplet. /// private const int detail = 50; - private readonly List controlPoints; + private readonly ReadOnlySpan controlPoints; - public CatmullApproximator(List controlPoints) + public CatmullApproximator(ReadOnlySpan controlPoints) { this.controlPoints = controlPoints; } - /// /// Creates a piecewise-linear approximation of a Catmull-Rom spline. /// /// A list of vectors representing the piecewise-linear approximation. public List CreateCatmull() { - var result = new List(); + var result = new List((controlPoints.Length - 1) * detail * 2); - for (int i = 0; i < controlPoints.Count - 1; i++) + for (int i = 0; i < controlPoints.Length - 1; i++) { var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; var v2 = controlPoints[i]; - var v3 = i < controlPoints.Count - 1 ? controlPoints[i + 1] : v2 + v2 - v1; - var v4 = i < controlPoints.Count - 2 ? controlPoints[i + 2] : v3 + v3 - v2; + var v3 = i < controlPoints.Length - 1 ? controlPoints[i + 1] : v2 + v2 - v1; + var v4 = i < controlPoints.Length - 2 ? controlPoints[i + 2] : v3 + v3 - v2; for (int c = 0; c < detail; c++) { diff --git a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs index 7fb8d8a40e..28d7442aaf 100644 --- a/osu.Game/Rulesets/Objects/CircularArcApproximator.cs +++ b/osu.Game/Rulesets/Objects/CircularArcApproximator.cs @@ -8,21 +8,15 @@ using OpenTK; namespace osu.Game.Rulesets.Objects { - public class CircularArcApproximator + public readonly ref struct CircularArcApproximator { - private readonly Vector2 a; - private readonly Vector2 b; - private readonly Vector2 c; - - private int amountPoints; - private const float tolerance = 0.1f; - public CircularArcApproximator(Vector2 a, Vector2 b, Vector2 c) + private readonly ReadOnlySpan controlPoints; + + public CircularArcApproximator(ReadOnlySpan controlPoints) { - this.a = a; - this.b = b; - this.c = c; + this.controlPoints = controlPoints; } /// @@ -31,6 +25,10 @@ namespace osu.Game.Rulesets.Objects /// A list of vectors representing the piecewise-linear approximation. public List CreateArc() { + Vector2 a = controlPoints[0]; + Vector2 b = controlPoints[1]; + Vector2 c = controlPoints[2]; + float aSq = (b - c).LengthSquared; float bSq = (a - c).LengthSquared; float cSq = (a - b).LengthSquared; @@ -81,7 +79,7 @@ namespace osu.Game.Rulesets.Objects // is: 2 * Math.Acos(1 - TOLERANCE / r) // The special case is required for extremely short sliders where the radius is smaller than // the tolerance. This is a pathological rather than a realistic case. - amountPoints = 2 * r <= tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(thetaRange / (2 * Math.Acos(1 - tolerance / r)))); + int amountPoints = 2 * r <= tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(thetaRange / (2 * Math.Acos(1 - tolerance / r)))); List output = new List(amountPoints); diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 802080aedb..9c9fc2e742 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 72168a4cd2..965e76d27a 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -72,10 +72,18 @@ namespace osu.Game.Rulesets.Objects.Legacy { CurveType curveType = CurveType.Catmull; double length = 0; - var points = new List { Vector2.Zero }; - string[] pointsplit = split[5].Split('|'); - foreach (string t in pointsplit) + string[] pointSplit = split[5].Split('|'); + + int pointCount = 1; + foreach (var t in pointSplit) + if (t.Length > 1) + pointCount++; + + var points = new Vector2[pointCount]; + + int pointIndex = 1; + foreach (string t in pointSplit) { if (t.Length == 1) { @@ -94,16 +102,18 @@ namespace osu.Game.Rulesets.Objects.Legacy curveType = CurveType.PerfectCurve; break; } + continue; } string[] temp = t.Split(':'); - points.Add(new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos); + points[pointIndex++] = new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos; } // osu-stable special-cased colinear perfect curves to a CurveType.Linear - bool isLinear(List p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y)); - if (points.Count == 3 && curveType == CurveType.PerfectCurve && isLinear(points)) + bool isLinear(Vector2[] p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y)); + + if (points.Length == 3 && curveType == CurveType.PerfectCurve && isLinear(points)) curveType = CurveType.Linear; int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture); @@ -262,7 +272,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The slider repeat count. /// The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider. /// The hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); /// /// Creates a legacy Spinner-type hit object. diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index ef1eecec3d..93c49ea3ce 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// s don't need a curve since they're converted to ruleset-specific hitobjects. /// public SliderCurve Curve { get; } = null; - public List ControlPoints { get; set; } + public Vector2[] ControlPoints { get; set; } public CurveType CurveType { get; set; } public double Distance { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 6f59965e18..68e05f6223 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index acd0de8688..f3c815fc32 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index e5904825c2..985a032640 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko return new ConvertHit(); } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { return new ConvertSlider { diff --git a/osu.Game/Rulesets/Objects/SliderCurve.cs b/osu.Game/Rulesets/Objects/SliderCurve.cs index 3932d8ed9d..60f7901a48 100644 --- a/osu.Game/Rulesets/Objects/SliderCurve.cs +++ b/osu.Game/Rulesets/Objects/SliderCurve.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.MathUtils; @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Objects { public double Distance; - public List ControlPoints; + public Vector2[] ControlPoints; public CurveType CurveType = CurveType.PerfectCurve; @@ -22,19 +23,17 @@ namespace osu.Game.Rulesets.Objects private readonly List calculatedPath = new List(); private readonly List cumulativeLength = new List(); - private List calculateSubpath(List subControlPoints) + private List calculateSubpath(ReadOnlySpan subControlPoints) { switch (CurveType) { - case CurveType.Linear: - return subControlPoints; case CurveType.PerfectCurve: //we can only use CircularArc iff we have exactly three control points and no dissection. - if (ControlPoints.Count != 3 || subControlPoints.Count != 3) + if (ControlPoints.Length != 3 || subControlPoints.Length != 3) break; // Here we have exactly 3 control points. Attempt to fit a circular arc. - List subpath = new CircularArcApproximator(subControlPoints[0], subControlPoints[1], subControlPoints[2]).CreateArc(); + List subpath = new CircularArcApproximator(subControlPoints).CreateArc(); // If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation. if (subpath.Count == 0) @@ -55,18 +54,32 @@ namespace osu.Game.Rulesets.Objects // Sliders may consist of various subpaths separated by two consecutive vertices // with the same position. The following loop parses these subpaths and computes // their shape independently, consecutively appending them to calculatedPath. - List subControlPoints = new List(); - for (int i = 0; i < ControlPoints.Count; ++i) - { - subControlPoints.Add(ControlPoints[i]); - if (i == ControlPoints.Count - 1 || ControlPoints[i] == ControlPoints[i + 1]) - { - List subpath = calculateSubpath(subControlPoints); - foreach (Vector2 t in subpath) - if (calculatedPath.Count == 0 || calculatedPath.Last() != t) - calculatedPath.Add(t); - subControlPoints.Clear(); + int start = 0; + int end = 0; + + for (int i = 0; i < ControlPoints.Length; ++i) + { + end++; + + if (i == ControlPoints.Length - 1 || ControlPoints[i] == ControlPoints[i + 1]) + { + ReadOnlySpan cpSpan = ControlPoints.AsSpan().Slice(start, end - start); + + if (CurveType == CurveType.Linear) + { + foreach (var t in cpSpan) + if (calculatedPath.Count == 0 || calculatedPath.Last() != t) + calculatedPath.Add(t); + } + else + { + foreach (Vector2 t in calculateSubpath(cpSpan)) + if (calculatedPath.Count == 0 || calculatedPath.Last() != t) + calculatedPath.Add(t); + } + + start = end; } } } @@ -166,7 +179,7 @@ namespace osu.Game.Rulesets.Objects /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). public void GetPathToProgress(List path, double p0, double p1) { - if (calculatedPath.Count == 0 && ControlPoints.Count > 0) + if (calculatedPath.Count == 0 && ControlPoints.Length > 0) Calculate(); double d0 = progressToDistance(p0); @@ -193,7 +206,7 @@ namespace osu.Game.Rulesets.Objects /// public Vector2 PositionAt(double progress) { - if (calculatedPath.Count == 0 && ControlPoints.Count > 0) + if (calculatedPath.Count == 0 && ControlPoints.Length > 0) Calculate(); double d = progressToDistance(progress); diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs index 54dcb26ae2..69b2f722e7 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using OpenTK; namespace osu.Game.Rulesets.Objects.Types @@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Objects.Types /// /// The control points that shape the curve. /// - List ControlPoints { get; } + Vector2[] ControlPoints { get; } /// /// The type of curve. From bd99a872988ba09a33ab837c3187abb34e78a3f6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 17:48:47 +0900 Subject: [PATCH 53/93] Use ordinal comparison in LegacyBeatmapDecoder --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 5b5bc5d936..d9f72315ee 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -58,7 +58,7 @@ namespace osu.Game.Beatmaps.Formats hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); } - protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(" ") || line.StartsWith("_"); + protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(" ", StringComparison.Ordinal) || line.StartsWith("_", StringComparison.Ordinal); protected override void ParseLine(Beatmap beatmap, Section section, string line) { From 5b544a0c97bf8fe29d93897abe4ba2a38244d3b2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 18:09:19 +0900 Subject: [PATCH 54/93] Remove allocation of string.IndexOf() --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index a9e1e4c55d..db1fe6b2ed 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -69,7 +69,9 @@ namespace osu.Game.Beatmaps.Formats protected string StripComments(string line) { - var index = line.IndexOf("//", StringComparison.Ordinal); + const string comment_prefix = "//"; + + var index = line.AsSpan().IndexOf(comment_prefix.AsSpan()); if (index > 0) return line.Substring(0, index); return line; From 10fb1d20d1c4498ec232d91f2ffdc8781ebeae61 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 18:38:04 +0900 Subject: [PATCH 55/93] Remove allocation of control point with every binarysearch --- .../Beatmaps/ControlPoints/ControlPointInfo.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index dad69321a5..2be7f4e16d 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -12,6 +12,11 @@ namespace osu.Game.Beatmaps.ControlPoints [Serializable] public class ControlPointInfo { + private readonly TimingControlPoint timingPointSearch = new TimingControlPoint(); + private readonly DifficultyControlPoint difficultyPointSearch = new DifficultyControlPoint(); + private readonly SampleControlPoint samplePointSearch = new SampleControlPoint(); + private readonly EffectControlPoint effectPointSearch = new EffectControlPoint(); + /// /// All timing points. /// @@ -41,28 +46,28 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the difficulty control point at. /// The difficulty control point. - public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time); + public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time, difficultyPointSearch); /// /// Finds the effect control point that is active at . /// /// The time to find the effect control point at. /// The effect control point. - public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time); + public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time, effectPointSearch); /// /// Finds the sound control point that is active at . /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.FirstOrDefault()); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, samplePointSearch, SamplePoints.FirstOrDefault()); /// /// Finds the timing control point that is active at . /// /// The time to find the timing control point at. /// The timing control point. - public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault()); + public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, timingPointSearch, TimingPoints.FirstOrDefault()); /// /// Finds the maximum BPM represented by any timing control point. @@ -92,7 +97,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. If null, a new control point will be constructed. /// The active control point at . - private T binarySearch(SortedList list, double time, T prePoint = null) + private T binarySearch(SortedList list, double time, T searchPoint, T prePoint = null) where T : ControlPoint, new() { if (list == null) @@ -104,7 +109,8 @@ namespace osu.Game.Beatmaps.ControlPoints if (time < list[0].Time) return prePoint ?? new T(); - int index = list.BinarySearch(new T { Time = time }); + searchPoint.Time = time; + int index = list.BinarySearch(searchPoint); // Check if we've found an exact match (t == time) if (index >= 0) From 7b2a30f5b4624481cd5ab23bb3e9b59d6712ac79 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 19:52:03 +0900 Subject: [PATCH 56/93] Reduce some high-profile enumerator allocations --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 2be7f4e16d..db5574e5ce 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -60,14 +60,14 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, samplePointSearch, SamplePoints.FirstOrDefault()); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, samplePointSearch, SamplePoints.Count > 0 ? SamplePoints[0] : null); /// /// Finds the timing control point that is active at . /// /// The time to find the timing control point at. /// The timing control point. - public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, timingPointSearch, TimingPoints.FirstOrDefault()); + public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, timingPointSearch, TimingPoints.Count > 0 ? TimingPoints[0] : null); /// /// Finds the maximum BPM represented by any timing control point. From ec9f23ab73849fff9b626f935b3e2c8ffbbc9b4e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 19:53:07 +0900 Subject: [PATCH 57/93] Make IBeatmap.HitObjects an IReadOnlyList --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Beatmaps/Patterns/Legacy/PatternGenerator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- osu.Game/Beatmaps/Beatmap.cs | 2 +- osu.Game/Beatmaps/IBeatmap.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index c15b303048..5d8480d969 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps TargetColumns = (int)Math.Max(1, roundedCircleSize); else { - float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count(); + float percentSliderOrSpinner = (float)beatmap.HitObjects.Count(h => h is IHasEndTime) / beatmap.HitObjects.Count; if (percentSliderOrSpinner < 0.2) TargetColumns = 7; else if (percentSliderOrSpinner < 0.3 || roundedCircleSize >= 5) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index 05ca1d4365..7bd39adb45 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy drainTime = 10000; BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty; - conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count() / drainTime * 9f) / 38f * 5f / 1.15; + conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); return conversionDifficulty.Value; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 028e3acc57..8fc2b69267 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double hitWindowGreat = (int)(beatmap.HitObjects.First().HitWindows.Great / 2) / timeRate; double preempt = (int)BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate; - int maxCombo = beatmap.HitObjects.Count(); + int maxCombo = beatmap.HitObjects.Count; // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above) maxCombo += beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index d4a60dd52f..b0887ac72b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); - beatmapMaxCombo = Beatmap.HitObjects.Count(); + beatmapMaxCombo = Beatmap.HitObjects.Count; // Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above) beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count - 1); } diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 9aabb434a3..4ef7b28d49 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -48,7 +48,7 @@ namespace osu.Game.Beatmaps [JsonConverter(typeof(TypedListConverter))] public List HitObjects = new List(); - IEnumerable IBeatmap.HitObjects => HitObjects; + IReadOnlyList IBeatmap.HitObjects => HitObjects; public virtual IEnumerable GetStatistics() => Enumerable.Empty(); diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index fe20bce98a..3d8b94dc46 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -39,7 +39,7 @@ namespace osu.Game.Beatmaps /// /// The hitobjects contained by this beatmap. /// - IEnumerable HitObjects { get; } + IReadOnlyList HitObjects { get; } /// /// Returns statistics for the contained in this beatmap. From fb1760f580ca6c6ec90526f6dd3fd7398e9decdb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 20:29:26 +0900 Subject: [PATCH 58/93] Simplify linq from beatmap conversion --- osu.Game/Beatmaps/BeatmapConverter.cs | 43 +++++++++++++-------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index a1bb70135a..6496a84803 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -55,39 +55,38 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo = original.BeatmapInfo; beatmap.ControlPointInfo = original.ControlPointInfo; - beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList(); + beatmap.HitObjects = convertHitObjects(original.HitObjects, original); beatmap.Breaks = original.Breaks; return beatmap; } - /// - /// Converts a hit object. - /// - /// The hit object to convert. - /// The un-converted Beatmap. - /// The converted hit object. - private IEnumerable convert(HitObject original, IBeatmap beatmap) + private List convertHitObjects(IReadOnlyList hitObjects, IBeatmap beatmap) { - // Check if the hitobject is already the converted type - T tObject = original as T; - if (tObject != null) - { - yield return tObject; - yield break; - } + var result = new List(hitObjects.Count); - var converted = ConvertHitObject(original, beatmap).ToList(); - ObjectConverted?.Invoke(original, converted); - - // Convert the hit object - foreach (var obj in converted) + // ReSharper disable once ForCanBeConvertedToForeach + foreach (var obj in hitObjects) { - if (obj == null) + if (obj is T tObj) + { + result.Add(tObj); continue; + } - yield return obj; + var converted = ConvertHitObject(obj, beatmap); + + // Note: This will not perform .ToList() if ObjectConverted is null + ObjectConverted?.Invoke(obj, converted.ToList()); + + foreach (var c in converted) + { + if (c != null) + result.Add(c); + } } + + return result; } /// From d282d16e1cb31595e4e140d8a49179a182ee8c98 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 20:49:12 +0900 Subject: [PATCH 59/93] Use SortedList again --- osu.Game/Rulesets/Objects/HitObject.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 67a3db7a00..f5613e927f 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Newtonsoft.Json; +using osu.Framework.Lists; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -55,7 +56,7 @@ namespace osu.Game.Rulesets.Objects /// public HitWindows HitWindows { get; set; } - private readonly List nestedHitObjects = new List(); + private readonly SortedList nestedHitObjects = new SortedList(compareObjects); [JsonIgnore] public IReadOnlyList NestedHitObjects => nestedHitObjects; @@ -73,8 +74,6 @@ namespace osu.Game.Rulesets.Objects CreateNestedHitObjects(); - nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); - foreach (var h in nestedHitObjects) { h.HitWindows = HitWindows; @@ -115,5 +114,7 @@ namespace osu.Game.Rulesets.Objects /// /// protected virtual HitWindows CreateHitWindows() => new HitWindows(); + + private static int compareObjects(HitObject first, HitObject second) => first.StartTime.CompareTo(second.StartTime); } } From c52a2929352280e75c32396db4a5a2ce2c9be413 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Oct 2018 16:10:32 +0900 Subject: [PATCH 60/93] Update framework --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 66bae277b3..9ff79550fa 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 72c8ae8705bae27510e112b311237f3df4ff749a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 12 Oct 2018 16:47:18 +0900 Subject: [PATCH 61/93] Port the old stacking algorithm --- .../Beatmaps/OsuBeatmapProcessor.cs | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs index cfb1b0f050..db80948c94 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs @@ -10,6 +10,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { public class OsuBeatmapProcessor : BeatmapProcessor { + private const int stack_distance = 3; + public OsuBeatmapProcessor(IBeatmap beatmap) : base(beatmap) { @@ -18,17 +20,21 @@ namespace osu.Game.Rulesets.Osu.Beatmaps public override void PostProcess() { base.PostProcess(); - applyStacking((Beatmap)Beatmap); + + var osuBeatmap = (Beatmap)Beatmap; + + // Reset stacking + foreach (var h in osuBeatmap.HitObjects) + h.StackHeight = 0; + + if (Beatmap.BeatmapInfo.BeatmapVersion >= 6) + applyStacking(osuBeatmap); + else + applyStackingOld(osuBeatmap); } private void applyStacking(Beatmap beatmap) { - const int stack_distance = 3; - - // Reset stacking - for (int i = 0; i <= beatmap.HitObjects.Count - 1; i++) - beatmap.HitObjects[i].StackHeight = 0; - // Extend the end index to include objects they are stacked on int extendedEndIndex = beatmap.HitObjects.Count - 1; for (int i = beatmap.HitObjects.Count - 1; i >= 0; i--) @@ -167,5 +173,40 @@ namespace osu.Game.Rulesets.Osu.Beatmaps } } } + + private void applyStackingOld(Beatmap beatmap) + { + for (int i = 0; i < beatmap.HitObjects.Count; i++) + { + OsuHitObject currHitObject = beatmap.HitObjects[i]; + + if (currHitObject.StackHeight != 0 && !(currHitObject is Slider)) + continue; + + double startTime = (currHitObject as IHasEndTime)?.EndTime ?? currHitObject.StartTime; + int sliderStack = 0; + + for (int j = i + 1; j < beatmap.HitObjects.Count; j++) + { + double stackThreshold = beatmap.HitObjects[i].TimePreempt * beatmap.BeatmapInfo.StackLeniency; + + if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime) + break; + + if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance) + { + currHitObject.StackHeight++; + startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime; + } + else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.EndPosition) < stack_distance) + { + //Case for sliders - bump notes down and right, rather than up and left. + sliderStack++; + beatmap.HitObjects[j].StackHeight -= sliderStack; + startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime; + } + } + } + } } } From 182aa63cc8acd7637d91cf95dd6bb685f2c59373 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Oct 2018 17:08:59 +0900 Subject: [PATCH 62/93] Update nuget dependencies --- osu.Desktop/osu.Desktop.csproj | 6 +++--- .../osu.Game.Rulesets.Catch.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 803927bc6f..1e8bf05e01 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -27,9 +27,9 @@ - - - + + + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 51343d9e91..9e89539e25 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -2,8 +2,8 @@ - - + + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 3165f69a6b..724614e8d5 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 247d5e18c1..69982b1914 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 08a0579561..11d6025f6d 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index d638af0c38..eb9d819fcb 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9ff79550fa..22e5901ed6 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -14,13 +14,13 @@ - + - + - + From 15dae9b2e44e12c78ffad179b7970d55184ccafe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Oct 2018 18:51:51 +0900 Subject: [PATCH 63/93] Update nuget dependencies (version mismatches) --- .../osu.Game.Rulesets.Catch.Tests.csproj | 1 + .../osu.Game.Rulesets.Mania.Tests.csproj | 3 ++- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 3 ++- .../osu.Game.Rulesets.Taiko.Tests.csproj | 3 ++- osu.Game.Tests/osu.Game.Tests.csproj | 3 ++- osu.Game/osu.Game.csproj | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 9e89539e25..326791f506 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -5,6 +5,7 @@ + WinExe diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 724614e8d5..bf75ebbff8 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -2,9 +2,10 @@ - + + WinExe diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 69982b1914..23c6150b6a 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -2,9 +2,10 @@ - + + WinExe diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 11d6025f6d..6ae9a018c5 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -2,9 +2,10 @@ - + + WinExe diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index eb9d819fcb..4e55e23aaf 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -2,9 +2,10 @@ - + + WinExe diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 22e5901ed6..cc21f4f6a4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -15,7 +15,7 @@ - + From 4a64cb7f85543cbb4813c1643b284407c30e93c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Oct 2018 18:55:12 +0900 Subject: [PATCH 64/93] Remove nuget includes im props --- osu.Game.Tests/osu.Game.Tests.csproj | 1 + osu.TestProject.props | 4 ---- osu.sln.DotSettings | 1 + 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 4e55e23aaf..520e0b8940 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -2,6 +2,7 @@ + diff --git a/osu.TestProject.props b/osu.TestProject.props index 506d634555..456ecfd468 100644 --- a/osu.TestProject.props +++ b/osu.TestProject.props @@ -10,10 +10,6 @@ - - - - VisualTestRunner.cs diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 404b19deda..345400305c 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -666,6 +666,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste True True True + True True True True From ad42f2244dc4ea7189a7fe96a326aac5414f1669 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Oct 2018 19:15:11 +0900 Subject: [PATCH 65/93] Add fallback logic in case a ruleset consumer forgets to add the HitObjectContainer --- osu.Game/Rulesets/UI/Playfield.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index f5db0cd3ce..886eb3ac0e 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -93,6 +93,15 @@ namespace osu.Game.Rulesets.UI nestedPlayfields.Value.Add(otherPlayfield); } + protected override void LoadComplete() + { + base.LoadComplete(); + + // in the case a consumer forgets to add the HitObjectContainer, we will add it here. + if (HitObjectContainer.Parent == null) + AddInternal(HitObjectContainer); + } + protected override void Update() { base.Update(); From 710b0a46648e2a005ac1d17a539035ceac5a795f Mon Sep 17 00:00:00 2001 From: HoLLy Date: Fri, 12 Oct 2018 15:30:24 +0200 Subject: [PATCH 66/93] Remove unnecessary PathSanitise call --- osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index a73a32325a..375c0b29c0 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -298,6 +298,6 @@ namespace osu.Game.Beatmaps.Formats } } - private string cleanFilename(string path) => FileSafety.PathStandardise(FileSafety.PathSanitise(path.Trim('\"'))); + private string cleanFilename(string path) => FileSafety.PathStandardise(path.Trim('"')); } } From 26b91c96fbfdc1568e79c39f1041d9b584914e1f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 15 Oct 2018 12:25:42 +0900 Subject: [PATCH 67/93] Fix wrong number of ticks on some legacy beatmaps --- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 3 ++- osu.Game.Rulesets.Osu/Objects/Slider.cs | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 9e0e649eb2..14245ec8ac 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -43,7 +43,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps Position = positionData?.Position ?? Vector2.Zero, NewCombo = comboData?.NewCombo ?? false, ComboOffset = comboData?.ComboOffset ?? 0, - LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset + LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset, + TickDistanceMultiplier = beatmap.BeatmapInfo.BeatmapVersion < 8 ? 1f / beatmap.ControlPointInfo.DifficultyPointAt(original.StartTime).SpeedMultiplier : 1 }; } else if (endTimeData != null) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 7a0dcc77a6..1901c852ed 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -95,6 +95,12 @@ namespace osu.Game.Rulesets.Osu.Objects public double Velocity; public double TickDistance; + /// + /// An extra multiplier that affects the number of ticks generated by this . + /// An increase in this value increases , which reduces the number of ticks generated. + /// + public double TickDistanceMultiplier = 1; + public HitCircle HeadCircle; public SliderTailCircle TailCircle; @@ -108,7 +114,7 @@ namespace osu.Game.Rulesets.Osu.Objects double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; Velocity = scoringDistance / timingPoint.BeatLength; - TickDistance = scoringDistance / difficulty.SliderTickRate; + TickDistance = scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier; } protected override void CreateNestedHitObjects() From 2f943e77aa29440460dbc36237cbe8a88f21fdc3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 15 Oct 2018 12:31:52 +0900 Subject: [PATCH 68/93] Make Velocity and TickDistance private set --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 4 ++-- osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 1901c852ed..85c5d7a30a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -92,8 +92,8 @@ namespace osu.Game.Rulesets.Osu.Objects /// public double SpanDuration => Duration / this.SpanCount(); - public double Velocity; - public double TickDistance; + public double Velocity { get; private set; } + public double TickDistance { get; private set; } /// /// An extra multiplier that affects the number of ticks generated by this . diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 5df371dd09..fe00821254 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -49,9 +49,7 @@ namespace osu.Game.Tests.Visual Vector2.Zero, new Vector2(216, 0), }, - Distance = 400, - Velocity = 1, - TickDistance = 100, + Distance = 216, Scale = 0.5f, } }, From 657bd5e37139dc10ac2b69015bb91c45d0f0b652 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 15 Oct 2018 12:32:59 +0900 Subject: [PATCH 69/93] Add some xmldocs --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 85c5d7a30a..4fc0d76e2b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -92,11 +92,18 @@ namespace osu.Game.Rulesets.Osu.Objects /// public double SpanDuration => Duration / this.SpanCount(); + /// + /// Velocity of this . + /// public double Velocity { get; private set; } + + /// + /// Spacing between s of this . + /// public double TickDistance { get; private set; } /// - /// An extra multiplier that affects the number of ticks generated by this . + /// An extra multiplier that affects the number of s generated by this . /// An increase in this value increases , which reduces the number of ticks generated. /// public double TickDistanceMultiplier = 1; From 72aaaa4a7426bb11a9e2bbe5859b4197654cfe9e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 10:29:53 +0900 Subject: [PATCH 70/93] PointSearch -> SearchPoint --- .../Beatmaps/ControlPoints/ControlPointInfo.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index db5574e5ce..4e36a755d1 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -12,10 +12,10 @@ namespace osu.Game.Beatmaps.ControlPoints [Serializable] public class ControlPointInfo { - private readonly TimingControlPoint timingPointSearch = new TimingControlPoint(); - private readonly DifficultyControlPoint difficultyPointSearch = new DifficultyControlPoint(); - private readonly SampleControlPoint samplePointSearch = new SampleControlPoint(); - private readonly EffectControlPoint effectPointSearch = new EffectControlPoint(); + private readonly TimingControlPoint timingSearchPoint = new TimingControlPoint(); + private readonly DifficultyControlPoint difficultySearchPoint = new DifficultyControlPoint(); + private readonly SampleControlPoint sampleSearchPoint = new SampleControlPoint(); + private readonly EffectControlPoint effectSearchPoint = new EffectControlPoint(); /// /// All timing points. @@ -46,28 +46,28 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the difficulty control point at. /// The difficulty control point. - public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time, difficultyPointSearch); + public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time, difficultySearchPoint); /// /// Finds the effect control point that is active at . /// /// The time to find the effect control point at. /// The effect control point. - public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time, effectPointSearch); + public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time, effectSearchPoint); /// /// Finds the sound control point that is active at . /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, samplePointSearch, SamplePoints.Count > 0 ? SamplePoints[0] : null); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, sampleSearchPoint, SamplePoints.Count > 0 ? SamplePoints[0] : null); /// /// Finds the timing control point that is active at . /// /// The time to find the timing control point at. /// The timing control point. - public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, timingPointSearch, TimingPoints.Count > 0 ? TimingPoints[0] : null); + public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, timingSearchPoint, TimingPoints.Count > 0 ? TimingPoints[0] : null); /// /// Finds the maximum BPM represented by any timing control point. From 060cc24dba4fef9e38ab56339aa6386839474bdd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 11:11:04 +0900 Subject: [PATCH 71/93] Cleanup slidercurve calculation --- osu.Game/Rulesets/Objects/SliderCurve.cs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/Objects/SliderCurve.cs b/osu.Game/Rulesets/Objects/SliderCurve.cs index 60f7901a48..dfccdf68f2 100644 --- a/osu.Game/Rulesets/Objects/SliderCurve.cs +++ b/osu.Game/Rulesets/Objects/SliderCurve.cs @@ -27,6 +27,12 @@ namespace osu.Game.Rulesets.Objects { switch (CurveType) { + case CurveType.Linear: + var result = new List(subControlPoints.Length); + foreach (var c in subControlPoints) + result.Add(c); + + return result; case CurveType.PerfectCurve: //we can only use CircularArc iff we have exactly three control points and no dissection. if (ControlPoints.Length != 3 || subControlPoints.Length != 3) @@ -66,18 +72,9 @@ namespace osu.Game.Rulesets.Objects { ReadOnlySpan cpSpan = ControlPoints.AsSpan().Slice(start, end - start); - if (CurveType == CurveType.Linear) - { - foreach (var t in cpSpan) - if (calculatedPath.Count == 0 || calculatedPath.Last() != t) - calculatedPath.Add(t); - } - else - { - foreach (Vector2 t in calculateSubpath(cpSpan)) - if (calculatedPath.Count == 0 || calculatedPath.Last() != t) - calculatedPath.Add(t); - } + foreach (Vector2 t in calculateSubpath(cpSpan)) + if (calculatedPath.Count == 0 || calculatedPath.Last() != t) + calculatedPath.Add(t); start = end; } From 3ad93d5a07f666ab6f790e324dfd8b29f5a97253 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 11:40:51 +0900 Subject: [PATCH 72/93] Remove redundant type specifications --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 2 +- osu.Game/Graphics/UserInterface/OsuTabControl.cs | 4 ++-- osu.Game/Graphics/UserInterface/RollingCounter.cs | 2 +- osu.Game/Storyboards/CommandTimeline.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 04a7cb64d3..30803d1545 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -30,7 +30,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(OsuColour colours) { - if (accentColour == default(Color4)) + if (accentColour == default) accentColour = colours.PinkDarker; updateAccentColour(); } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 24183e07a0..e7d6a87349 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -53,7 +53,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(OsuColour colours) { - if (accentColour == default(Color4)) + if (accentColour == default) AccentColour = colours.Blue; } @@ -142,7 +142,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(OsuColour colours) { - if (accentColour == default(Color4)) + if (accentColour == default) AccentColour = colours.Blue; } diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs index f84404a911..c2162b8a42 100644 --- a/osu.Game/Graphics/UserInterface/RollingCounter.cs +++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs @@ -134,7 +134,7 @@ namespace osu.Game.Graphics.UserInterface /// public virtual void ResetCount() { - SetCountWithoutRolling(default(T)); + SetCountWithoutRolling(default); } /// diff --git a/osu.Game/Storyboards/CommandTimeline.cs b/osu.Game/Storyboards/CommandTimeline.cs index 8a032064d3..64b0a45fcd 100644 --- a/osu.Game/Storyboards/CommandTimeline.cs +++ b/osu.Game/Storyboards/CommandTimeline.cs @@ -21,8 +21,8 @@ namespace osu.Game.Storyboards private Cached endTimeBacking; public double EndTime => endTimeBacking.IsValid ? endTimeBacking : endTimeBacking.Value = HasCommands ? commands.Max(c => c.EndTime) : double.MaxValue; - public T StartValue => HasCommands ? commands.OrderBy(c => c.StartTime).First().StartValue : default(T); - public T EndValue => HasCommands ? commands.OrderByDescending(c => c.EndTime).First().EndValue : default(T); + public T StartValue => HasCommands ? commands.OrderBy(c => c.StartTime).First().StartValue : default; + public T EndValue => HasCommands ? commands.OrderByDescending(c => c.EndTime).First().EndValue : default; public void Add(Easing easing, double startTime, double endTime, T startValue, T endValue) { From 41391a66278494926572fa8d60cf758afa14307a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Oct 2018 12:01:58 +0900 Subject: [PATCH 73/93] Fix beatmap conversion tests failing --- osu.Game/Beatmaps/BeatmapConverter.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index 6496a84803..a2d7a69b5d 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -76,8 +76,11 @@ namespace osu.Game.Beatmaps var converted = ConvertHitObject(obj, beatmap); - // Note: This will not perform .ToList() if ObjectConverted is null - ObjectConverted?.Invoke(obj, converted.ToList()); + if (ObjectConverted != null) + { + converted = converted.ToList(); + ObjectConverted.Invoke(obj, converted); + } foreach (var c in converted) { From eb9199e07ae40fbf73cb9a447ea17996f49b6799 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Tue, 16 Oct 2018 08:29:47 +0200 Subject: [PATCH 74/93] Run database migration unconditionally, remove downwards migration --- .../20181007180454_StandardizePaths.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.cs index 08b34507ce..e1b46dd018 100644 --- a/osu.Game/Migrations/20181007180454_StandardizePaths.cs +++ b/osu.Game/Migrations/20181007180454_StandardizePaths.cs @@ -11,10 +11,6 @@ namespace osu.Game.Migrations string sanitized = Path.DirectorySeparatorChar.ToString(); string standardized = "/"; - // If we are not on Windows, no changes are needed. - if (string.Equals(standardized, sanitized, StringComparison.Ordinal)) - return; - // Escaping \ does not seem to be needed. migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{sanitized}', '{standardized}')"); migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{sanitized}', '{standardized}')"); @@ -25,18 +21,6 @@ namespace osu.Game.Migrations protected override void Down(MigrationBuilder migrationBuilder) { - string sanitized = Path.DirectorySeparatorChar.ToString(); - string standardized = "/"; - - // If we are not on Windows, no changes are needed. - if (string.Equals(standardized, sanitized, StringComparison.Ordinal)) - return; - - migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{standardized}', '{sanitized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{standardized}', '{sanitized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `BackgroundFile` = REPLACE(`BackgroundFile`, '{standardized}', '{sanitized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapSetFileInfo` SET `Filename` = REPLACE(`Filename`, '{standardized}', '{sanitized}')"); - migrationBuilder.Sql($"UPDATE `SkinFileInfo` SET `Filename` = REPLACE(`Filename`, '{standardized}', '{sanitized}')"); } } } From d431dd59a8a12e43ed9c3310d5ebbe9b15acab09 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 10:53:21 +0900 Subject: [PATCH 75/93] Cleanups --- osu.Game/Beatmaps/BeatmapConverter.cs | 1 - osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index a2d7a69b5d..3cb7833a12 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -65,7 +65,6 @@ namespace osu.Game.Beatmaps { var result = new List(hitObjects.Count); - // ReSharper disable once ForCanBeConvertedToForeach foreach (var obj in hitObjects) { if (obj is T tObj) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index db1fe6b2ed..2ef7c5de30 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -69,9 +69,7 @@ namespace osu.Game.Beatmaps.Formats protected string StripComments(string line) { - const string comment_prefix = "//"; - - var index = line.AsSpan().IndexOf(comment_prefix.AsSpan()); + var index = line.AsSpan().IndexOf("//".AsSpan()); if (index > 0) return line.Substring(0, index); return line; From 336b6fa38ef95f7047f56c86044d1867064935be Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 11:23:18 +0900 Subject: [PATCH 76/93] Perform a custom binary search to remove thread-unsafeness --- .../ControlPoints/ControlPointInfo.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 4e36a755d1..d5826e85b0 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -12,11 +12,6 @@ namespace osu.Game.Beatmaps.ControlPoints [Serializable] public class ControlPointInfo { - private readonly TimingControlPoint timingSearchPoint = new TimingControlPoint(); - private readonly DifficultyControlPoint difficultySearchPoint = new DifficultyControlPoint(); - private readonly SampleControlPoint sampleSearchPoint = new SampleControlPoint(); - private readonly EffectControlPoint effectSearchPoint = new EffectControlPoint(); - /// /// All timing points. /// @@ -46,28 +41,28 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time to find the difficulty control point at. /// The difficulty control point. - public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time, difficultySearchPoint); + public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time); /// /// Finds the effect control point that is active at . /// /// The time to find the effect control point at. /// The effect control point. - public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time, effectSearchPoint); + public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time); /// /// Finds the sound control point that is active at . /// /// The time to find the sound control point at. /// The sound control point. - public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, sampleSearchPoint, SamplePoints.Count > 0 ? SamplePoints[0] : null); + public SampleControlPoint SamplePointAt(double time) => binarySearch(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : null); /// /// Finds the timing control point that is active at . /// /// The time to find the timing control point at. /// The timing control point. - public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, timingSearchPoint, TimingPoints.Count > 0 ? TimingPoints[0] : null); + public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : null); /// /// Finds the maximum BPM represented by any timing control point. @@ -97,7 +92,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. If null, a new control point will be constructed. /// The active control point at . - private T binarySearch(SortedList list, double time, T searchPoint, T prePoint = null) + private T binarySearch(SortedList list, double time, T prePoint = null) where T : ControlPoint, new() { if (list == null) @@ -109,18 +104,23 @@ namespace osu.Game.Beatmaps.ControlPoints if (time < list[0].Time) return prePoint ?? new T(); - searchPoint.Time = time; - int index = list.BinarySearch(searchPoint); + int l = 0; + int r = list.Count - 1; - // Check if we've found an exact match (t == time) - if (index >= 0) - return list[index]; + while (l <= r) + { + int pivot = l + ((r - l) >> 1); - index = ~index; + if (list[pivot].Time < time) + l = pivot + 1; + else if (list[pivot].Time > time) + r = pivot - 1; + else + return list[pivot]; + } - // BinarySearch will return the index of the first element _greater_ than the search - // This is the inactive point - the active point is the one before it (index - 1) - return list[index - 1]; + // l will be the first control point with Time > time, but we want the one before it + return list[l - 1]; } } } From 1bebceada7084e10f1a1df80f955c0d98cd5ba73 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Oct 2018 11:39:29 +0900 Subject: [PATCH 77/93] Unroll loop for the last control point --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index d5826e85b0..f064d53358 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -104,8 +104,11 @@ namespace osu.Game.Beatmaps.ControlPoints if (time < list[0].Time) return prePoint ?? new T(); + if (time >= list[list.Count - 1].Time) + return list[list.Count - 1]; + int l = 0; - int r = list.Count - 1; + int r = list.Count - 2; while (l <= r) { From a6d05febff65539ae34163b6e69c588d9ac2fb74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Oct 2018 16:26:41 +0900 Subject: [PATCH 78/93] Attempt with different key source --- appveyor_deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml index 22a4859885..355f0603be 100644 --- a/appveyor_deploy.yml +++ b/appveyor_deploy.yml @@ -10,8 +10,8 @@ before_build: - cmd: nuget restore -verbosity quiet build_script: - ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) - - appveyor DownloadFile https://puu.sh/BCrS8/7faccf7876.enc # signing certificate - - cmd: appveyor-tools\secure-file -decrypt 7faccf7876.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx + - appveyor DownloadFile https://www.dropbox.com/s/f7hv069mr5tqi2j/deanherbert.pfx.enc?dl=1 # signing certificate + - cmd: appveyor-tools\secure-file -decrypt deanherbert.pfx.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx - appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration - cd osu-deploy - nuget restore -verbosity quiet From 9aeba149f664806fc15029ad17bbaaa1387d8a3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Oct 2018 19:39:32 +0900 Subject: [PATCH 79/93] Update squirrel for more diagnostics --- osu.Desktop/osu.Desktop.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 1e8bf05e01..2be352165e 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -27,7 +27,7 @@ - + From 7720fa10eb075ce7fc1318958129860590e78c63 Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Wed, 17 Oct 2018 20:19:01 -0400 Subject: [PATCH 80/93] Reduce height of RankChartLineGraph --- osu.Game/Overlays/Profile/Header/RankGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/RankGraph.cs b/osu.Game/Overlays/Profile/Header/RankGraph.cs index fc80370cf9..bfb01ce1c8 100644 --- a/osu.Game/Overlays/Profile/Header/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/RankGraph.cs @@ -74,7 +74,7 @@ namespace osu.Game.Overlays.Profile.Header Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, - Height = 75, + Height = 60, Y = -secondary_textsize, Alpha = 0, } From 1cf6cd10bb1dc1fa87217c9e4e0b1d03088d7096 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 18 Oct 2018 11:29:50 +0900 Subject: [PATCH 81/93] Fix slider travel distances sometimes not being considered --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index ccfcc1ef25..d6684f55af 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -75,15 +75,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { computeSliderCursorPosition(lastSlider); lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition; + + TravelDistance = lastSlider.LazyTravelDistance * scalingFactor; } // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; - - // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also a slider! - if (BaseObject is Slider) - TravelDistance = (lastSlider?.LazyTravelDistance ?? 0) * scalingFactor; } private void setTimingValues() From d284f29637b2afddfced8c1dbcb74dcd20814938 Mon Sep 17 00:00:00 2001 From: Dan Balasescu <1329837+smoogipoo@users.noreply.github.com> Date: Thu, 18 Oct 2018 14:16:46 +0900 Subject: [PATCH 82/93] Add comment describing the speed multiplier --- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 14245ec8ac..b8aae1c28f 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -44,6 +44,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps NewCombo = comboData?.NewCombo ?? false, ComboOffset = comboData?.ComboOffset ?? 0, LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset, + // prior to v8, speed multipliers don't affect how many ticks are generated. TickDistanceMultiplier = beatmap.BeatmapInfo.BeatmapVersion < 8 ? 1f / beatmap.ControlPointInfo.DifficultyPointAt(original.StartTime).SpeedMultiplier : 1 }; } From 3f185a44defeabc22d662e0938553cf594230098 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Thu, 18 Oct 2018 08:29:12 +0200 Subject: [PATCH 83/93] Fix Windows-style path separators not being migrated on Unix systems --- .../Migrations/20181007180454_StandardizePaths.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.cs index e1b46dd018..274b8030a9 100644 --- a/osu.Game/Migrations/20181007180454_StandardizePaths.cs +++ b/osu.Game/Migrations/20181007180454_StandardizePaths.cs @@ -8,15 +8,15 @@ namespace osu.Game.Migrations { protected override void Up(MigrationBuilder migrationBuilder) { - string sanitized = Path.DirectorySeparatorChar.ToString(); + string windowsStyle = @"\"; string standardized = "/"; // Escaping \ does not seem to be needed. - migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{sanitized}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{sanitized}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `BackgroundFile` = REPLACE(`BackgroundFile`, '{sanitized}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapSetFileInfo` SET `Filename` = REPLACE(`Filename`, '{sanitized}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `SkinFileInfo` SET `Filename` = REPLACE(`Filename`, '{sanitized}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{windowsStyle}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{windowsStyle}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `BackgroundFile` = REPLACE(`BackgroundFile`, '{windowsStyle}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `BeatmapSetFileInfo` SET `Filename` = REPLACE(`Filename`, '{windowsStyle}', '{standardized}')"); + migrationBuilder.Sql($"UPDATE `SkinFileInfo` SET `Filename` = REPLACE(`Filename`, '{windowsStyle}', '{standardized}')"); } protected override void Down(MigrationBuilder migrationBuilder) From ae94aab677e8654eeb3ec93b578f3355e44e0459 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Oct 2018 20:50:36 +0900 Subject: [PATCH 84/93] Update framework --- osu.Desktop/osu.Desktop.csproj | 2 +- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 2be352165e..e1e59804e5 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -27,7 +27,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index cc21f4f6a4..26004b513f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 86b29064c6ed6e476dc4b05f674e10cbf5554b0a Mon Sep 17 00:00:00 2001 From: Paul Teng Date: Thu, 18 Oct 2018 08:51:05 -0400 Subject: [PATCH 85/93] Change DownloadState only when Download is possible --- osu.Game/Beatmaps/BeatmapManager.cs | 8 +++++--- osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index aa653d88f9..fad94dcdfd 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -148,11 +148,12 @@ namespace osu.Game.Beatmaps /// /// The to be downloaded. /// Whether the beatmap should be downloaded without video. Defaults to false. - public void Download(BeatmapSetInfo beatmapSetInfo, bool noVideo = false) + /// Downloading can happen + public bool Download(BeatmapSetInfo beatmapSetInfo, bool noVideo = false) { var existing = GetExistingDownload(beatmapSetInfo); - if (existing != null || api == null) return; + if (existing != null || api == null) return false; if (!api.LocalUser.Value.IsSupporter) { @@ -161,7 +162,7 @@ namespace osu.Game.Beatmaps Icon = FontAwesome.fa_superpowers, Text = "You gotta be an osu!supporter to download for now 'yo" }); - return; + return false; } var downloadNotification = new DownloadNotification @@ -227,6 +228,7 @@ namespace osu.Game.Beatmaps // don't run in the main api queue as this is a long-running task. Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning); BeatmapDownloadBegan?.Invoke(request); + return true; } protected override void PresentCompletedImport(IEnumerable imported) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs index 6f4d4c0d6f..de19c24d2f 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs @@ -71,9 +71,10 @@ namespace osu.Game.Beatmaps.Drawables if (DownloadState.Value > DownloadStatus.NotDownloaded) return; - beatmaps.Download(set, noVideo); - - DownloadState.Value = DownloadStatus.Downloading; + if (beatmaps.Download(set, noVideo)) { + // Only change state if download can happen + DownloadState.Value = DownloadStatus.Downloading; + } } private void setAdded(BeatmapSetInfo s) From 39fb7ac743ab7f818bd3b8380c53e4bb6245fe0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Oct 2018 20:32:14 +0900 Subject: [PATCH 86/93] Remove deploy configuration Has been moved to buildkite. --- appveyor_deploy.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 appveyor_deploy.yml diff --git a/appveyor_deploy.yml b/appveyor_deploy.yml deleted file mode 100644 index 355f0603be..0000000000 --- a/appveyor_deploy.yml +++ /dev/null @@ -1,30 +0,0 @@ -clone_depth: 1 -version: '{build}' -skip_non_tags: true -image: Visual Studio 2017 -install: - - git clone https://github.com/ppy/osu-deploy -before_build: - - ps: if($env:appveyor_repo_tag -eq 'True') { Update-AppveyorBuild -Version $env:appveyor_repo_tag_name } - - cmd: git submodule update --init --recursive --depth=5 - - cmd: nuget restore -verbosity quiet -build_script: - - ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) - - appveyor DownloadFile https://www.dropbox.com/s/f7hv069mr5tqi2j/deanherbert.pfx.enc?dl=1 # signing certificate - - cmd: appveyor-tools\secure-file -decrypt deanherbert.pfx.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx - - appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration - - cd osu-deploy - - nuget restore -verbosity quiet - - msbuild osu.Desktop.Deploy.csproj - - cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\netcoreapp2.1\osu.Desktop.Deploy.dll.config - - dotnet bin/Debug/netcoreapp2.1/osu.Desktop.Deploy.dll %code_signing_password% %APPVEYOR_REPO_TAG_NAME% -environment: - decode_secret: - secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY= - code_signing_password: - secure: 34tLNqvjmmZEi97MLKfrnQ== -artifacts: - - path: 'osu-deploy/releases/*' -deploy: - - provider: Environment - name: github \ No newline at end of file From 0952c20c84d3ea40c9835b03ba1a1fd2566174ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 20 Oct 2018 23:06:48 +0900 Subject: [PATCH 87/93] Adjust comment slightly --- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index b8aae1c28f..5b8a7acf58 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps NewCombo = comboData?.NewCombo ?? false, ComboOffset = comboData?.ComboOffset ?? 0, LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset, - // prior to v8, speed multipliers don't affect how many ticks are generated. + // prior to v8, speed multipliers don't adjust for how many ticks are generated over the same distance. TickDistanceMultiplier = beatmap.BeatmapInfo.BeatmapVersion < 8 ? 1f / beatmap.ControlPointInfo.DifficultyPointAt(original.StartTime).SpeedMultiplier : 1 }; } From f19cc98e6aa43a8b4d792bb1fedbefd7065da1f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 20 Oct 2018 23:10:33 +0900 Subject: [PATCH 88/93] Add slightly more explanation --- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 5b8a7acf58..b2914d4b82 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -45,6 +45,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps ComboOffset = comboData?.ComboOffset ?? 0, LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset, // prior to v8, speed multipliers don't adjust for how many ticks are generated over the same distance. + // this results in more (or less) ticks being generated in Date: Mon, 22 Oct 2018 12:17:23 +0900 Subject: [PATCH 89/93] Move brace on new line --- osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs index de19c24d2f..5b5dbec9c8 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetDownloader.cs @@ -71,7 +71,8 @@ namespace osu.Game.Beatmaps.Drawables if (DownloadState.Value > DownloadStatus.NotDownloaded) return; - if (beatmaps.Download(set, noVideo)) { + if (beatmaps.Download(set, noVideo)) + { // Only change state if download can happen DownloadState.Value = DownloadStatus.Downloading; } From 8a2a6a3ecbf7cc9507c66b601a17a917a1d6fe58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 23 Oct 2018 14:38:27 +0900 Subject: [PATCH 90/93] Preserve the beatmap's version --- .../Formats/LegacyBeatmapDecoderTest.cs | 21 +++++++++++++++++++ osu.Game.Tests/Resources/beatmap-version.osu | 1 + osu.Game/Beatmaps/BeatmapInfo.cs | 1 - osu.Game/Beatmaps/WorkingBeatmap.cs | 7 ++++++- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Resources/beatmap-version.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index af63a39662..f1ae366ee1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -8,11 +8,13 @@ using OpenTK.Graphics; using osu.Game.Tests.Resources; using System.Linq; using osu.Game.Audio; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Skinning; @@ -21,6 +23,25 @@ namespace osu.Game.Tests.Beatmaps.Formats [TestFixture] public class LegacyBeatmapDecoderTest { + [Test] + public void TestDecodeBeatmapVersion() + { + using (var resStream = Resource.OpenResource("beatmap-version.osu")) + using (var stream = new StreamReader(resStream)) + { + var decoder = Decoder.GetDecoder(stream); + + stream.BaseStream.Position = 0; + stream.DiscardBufferedData(); + + var working = new TestWorkingBeatmap(decoder.Decode(stream)); + + Assert.AreEqual(6, working.BeatmapInfo.BeatmapVersion); + Assert.AreEqual(6, working.Beatmap.BeatmapInfo.BeatmapVersion); + Assert.AreEqual(6, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapVersion); + } + } + [Test] public void TestDecodeBeatmapGeneral() { diff --git a/osu.Game.Tests/Resources/beatmap-version.osu b/osu.Game.Tests/Resources/beatmap-version.osu new file mode 100644 index 0000000000..5749054ac4 --- /dev/null +++ b/osu.Game.Tests/Resources/beatmap-version.osu @@ -0,0 +1 @@ +osu file format v6 \ No newline at end of file diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 1aa4818393..3e1f3bdf54 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -19,7 +19,6 @@ namespace osu.Game.Beatmaps [JsonIgnore] public int ID { get; set; } - //TODO: should be in database public int BeatmapVersion; private int? onlineBeatmapID; diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index e0a22460ef..5b76122616 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -41,8 +41,13 @@ namespace osu.Game.Beatmaps beatmap = new RecyclableLazy(() => { var b = GetBeatmap() ?? new Beatmap(); - // use the database-backed info. + + // The original beatmap version needs to be preserved as the database doesn't contain it + BeatmapInfo.BeatmapVersion = b.BeatmapInfo.BeatmapVersion; + + // Use the database-backed info for more up-to-date values (beatmap id, ranked status, etc) b.BeatmapInfo = BeatmapInfo; + return b; }); From 94093ac9488c5065737cd20f731a458dd16ef722 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Oct 2018 18:04:38 +0900 Subject: [PATCH 91/93] Update beatmap search API to match latest osu-web structure --- .../API/Requests/SearchBeatmapSetsRequest.cs | 6 +++--- .../API/Requests/SearchBeatmapSetsResponse.cs | 20 +++++++++++++++++++ osu.Game/Overlays/DirectOverlay.cs | 2 +- 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 3c808d1bee..ffea7b83e1 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -1,16 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using System.ComponentModel; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Direct; using osu.Game.Rulesets; namespace osu.Game.Online.API.Requests { - public class SearchBeatmapSetsRequest : APIRequest> + public class SearchBeatmapSetsRequest : APIRequest { private readonly string query; private readonly RulesetInfo ruleset; @@ -35,6 +33,7 @@ namespace osu.Game.Online.API.Requests public enum BeatmapSearchCategory { Any = 7, + [Description("Ranked & Approved")] RankedApproved = 0, Approved = 1, @@ -43,6 +42,7 @@ namespace osu.Game.Online.API.Requests Qualified = 3, Pending = 4, Graveyard = 5, + [Description("My Maps")] MyMaps = 6, } diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs new file mode 100644 index 0000000000..cf8b40d068 --- /dev/null +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsResponse.cs @@ -0,0 +1,20 @@ +// 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 Newtonsoft.Json; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class SearchBeatmapSetsResponse + { + public IEnumerable BeatmapSets; + + /// + /// A collection of parameters which should be passed to the search endpoint to fetch the next page. + /// + [JsonProperty("cursor")] + public dynamic CursorJson; + } +} diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index f63d314053..641f57d25f 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -288,7 +288,7 @@ namespace osu.Game.Overlays { Task.Run(() => { - var sets = response.Select(r => r.ToBeatmapSet(rulesets)).ToList(); + var sets = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList(); // may not need scheduling; loads async internally. Schedule(() => From 88aca465006312db05761539387e3e67605f0e8d Mon Sep 17 00:00:00 2001 From: HoLLy Date: Wed, 24 Oct 2018 18:53:22 +0200 Subject: [PATCH 92/93] Fade MetadataSection back in if non-null Text is set --- osu.Game/Screens/Select/BeatmapDetails.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index f7b955941d..9a16c76c44 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -341,6 +341,7 @@ namespace osu.Game.Screens.Select return; } + this.FadeIn(transition_duration); setTextAsync(value); } } From cf3b4447eb04413d0b3de61500abf417d9c0ee68 Mon Sep 17 00:00:00 2001 From: HoLLy Date: Fri, 26 Oct 2018 13:35:51 +0200 Subject: [PATCH 93/93] Fade only textContainer instead of entire MetadataSection --- osu.Game/Screens/Select/BeatmapDetails.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 9a16c76c44..3999adfede 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -307,10 +307,10 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Alpha = 0; InternalChild = textContainer = new FillFlowContainer { + Alpha = 0, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(spacing / 2), @@ -337,17 +337,14 @@ namespace osu.Game.Screens.Select { if (string.IsNullOrEmpty(value)) { - this.FadeOut(transition_duration); + textContainer.FadeOut(transition_duration); return; } - this.FadeIn(transition_duration); setTextAsync(value); } } - public override bool IsPresent => base.IsPresent || textFlow == null; // Visibility is updated in the LoadComponentAsync callback - private void setTextAsync(string text) { LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14) @@ -362,7 +359,7 @@ namespace osu.Game.Screens.Select textContainer.Add(textFlow = loaded); // fade in if we haven't yet. - this.FadeIn(transition_duration); + textContainer.FadeIn(transition_duration); }); } }