From f64fe22f3669cd2117a295d490ecd6a9f14b8f0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 27 Sep 2019 18:00:24 +0900 Subject: [PATCH 01/30] Remove bindables from osu! selection blueprints --- .../HitCircles/Components/HitCirclePiece.cs | 10 +++++++--- .../Edit/Blueprints/HitObjectPiece.cs | 19 ++----------------- .../Edit/Blueprints/SliderPiece.cs | 17 +++-------------- .../Components/PathControlPointVisualiser.cs | 9 ++------- .../Sliders/Components/SliderBodyPiece.cs | 6 +++--- .../Sliders/Components/SliderCirclePiece.cs | 12 ------------ .../Spinners/Components/SpinnerPiece.cs | 12 +++++++----- 7 files changed, 24 insertions(+), 61 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index fe11ead94d..99928cdad9 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -31,10 +31,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components private void load(OsuColour colours) { Colour = colours.Yellow; + } - PositionBindable.BindValueChanged(_ => UpdatePosition(), true); - StackHeightBindable.BindValueChanged(_ => UpdatePosition()); - ScaleBindable.BindValueChanged(scale => Scale = new Vector2(scale.NewValue), true); + protected override void Update() + { + base.Update(); + + UpdatePosition(); + Scale = new Vector2(hitCircle.Scale); } protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs index 315a5a2b9d..3d7d609c6b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; -using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { @@ -14,23 +11,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints /// public abstract class HitObjectPiece : CompositeDrawable { - protected readonly IBindable PositionBindable = new Bindable(); - protected readonly IBindable StackHeightBindable = new Bindable(); - protected readonly IBindable ScaleBindable = new Bindable(); - - private readonly OsuHitObject hitObject; + protected readonly OsuHitObject HitObject; protected HitObjectPiece(OsuHitObject hitObject) { - this.hitObject = hitObject; - } - - [BackgroundDependencyLoader] - private void load() - { - PositionBindable.BindTo(hitObject.PositionBindable); - StackHeightBindable.BindTo(hitObject.StackHeightBindable); - ScaleBindable.BindTo(hitObject.ScaleBindable); + HitObject = hitObject; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs index 8fd1d6d6f9..e0fcf8a000 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs @@ -1,32 +1,21 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { /// - /// A piece of a blueprint which responds to changes in the state of a . + /// A piece of a blueprint which responds to changes in the state of a . /// public abstract class SliderPiece : HitObjectPiece { - protected readonly IBindable PathBindable = new Bindable(); - - private readonly Slider slider; + protected readonly Slider Slider; protected SliderPiece(Slider slider) : base(slider) { - this.slider = slider; - } - - [BackgroundDependencyLoader] - private void load() - { - PathBindable.BindTo(slider.PathBindable); + Slider = slider; } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index df846b5d5b..3d8e014551 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; @@ -22,14 +21,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; } - [BackgroundDependencyLoader] - private void load() + protected override void Update() { - PathBindable.BindValueChanged(_ => updatePathControlPoints(), true); - } + base.Update(); - private void updatePathControlPoints() - { while (slider.Path.ControlPoints.Length > pieces.Count) pieces.Add(new PathControlPointPiece(slider, pieces.Count)); while (slider.Path.ControlPoints.Length < pieces.Count) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index f1f55731b6..aea17a4b8f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -31,9 +31,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private void load(OsuColour colours) { body.BorderColour = colours.Yellow; - - PositionBindable.BindValueChanged(_ => updatePosition(), true); - ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * OsuHitObject.OBJECT_RADIUS, true); } private void updatePosition() => Position = slider.StackedPosition; @@ -42,6 +39,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { base.Update(); + Position = slider.StackedPosition; + body.PathRadius = HitObject.Scale * OsuHitObject.OBJECT_RADIUS; + var vertices = new List(); slider.Path.GetPathToProgress(vertices, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs index 2ecfea2e3e..ec3a1d0034 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; @@ -11,8 +8,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class SliderCirclePiece : HitCirclePiece { - private readonly IBindable pathBindable = new Bindable(); - private readonly Slider slider; private readonly SliderPosition position; @@ -23,13 +18,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components this.position = position; } - [BackgroundDependencyLoader] - private void load() - { - pathBindable.BindTo(slider.PathBindable); - pathBindable.BindValueChanged(_ => UpdatePosition(), true); - } - protected override void UpdatePosition() { switch (position) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index ae94848c81..e2084bbb7c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -52,13 +52,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components private void load(OsuColour colours) { Colour = colours.Yellow; - - PositionBindable.BindValueChanged(_ => updatePosition(), true); - StackHeightBindable.BindValueChanged(_ => updatePosition()); - ScaleBindable.BindValueChanged(scale => ring.Scale = new Vector2(scale.NewValue), true); } - private void updatePosition() => Position = spinner.Position; + protected override void Update() + { + base.Update(); + + Position = spinner.Position; + ring.Scale = new Vector2(spinner.Scale); + } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); } From 4fc37d11376980b2fc34c616b247e8fbaca8b640 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 27 Sep 2019 18:01:55 +0900 Subject: [PATCH 02/30] Remove SliderPiece + HitObjectPiece --- .../HitCircles/Components/HitCirclePiece.cs | 4 ++-- .../Edit/Blueprints/HitObjectPiece.cs | 21 ------------------- .../Edit/Blueprints/SliderPiece.cs | 21 ------------------- .../Components/PathControlPointVisualiser.cs | 3 +-- .../Sliders/Components/SliderBodyPiece.cs | 6 +++--- .../Spinners/Components/SpinnerPiece.cs | 3 +-- 6 files changed, 7 insertions(+), 51 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index 99928cdad9..5e46b3ace4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -10,12 +11,11 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCirclePiece : HitObjectPiece + public class HitCirclePiece : CompositeDrawable { private readonly HitCircle hitCircle; public HitCirclePiece(HitCircle hitCircle) - : base(hitCircle) { this.hitCircle = hitCircle; Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs deleted file mode 100644 index 3d7d609c6b..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitObjectPiece.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Blueprints -{ - /// - /// A piece of a blueprint which responds to changes in the state of a . - /// - public abstract class HitObjectPiece : CompositeDrawable - { - protected readonly OsuHitObject HitObject; - - protected HitObjectPiece(OsuHitObject hitObject) - { - HitObject = hitObject; - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs deleted file mode 100644 index e0fcf8a000..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/SliderPiece.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Blueprints -{ - /// - /// A piece of a blueprint which responds to changes in the state of a . - /// - public abstract class SliderPiece : HitObjectPiece - { - protected readonly Slider Slider; - - protected SliderPiece(Slider slider) - : base(slider) - { - Slider = slider; - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 3d8e014551..24fcc460d1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -7,14 +7,13 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointVisualiser : SliderPiece + public class PathControlPointVisualiser : CompositeDrawable { private readonly Slider slider; private readonly Container pieces; public PathControlPointVisualiser(Slider slider) - : base(slider) { this.slider = slider; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index aea17a4b8f..239feee431 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -11,13 +12,12 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class SliderBodyPiece : SliderPiece + public class SliderBodyPiece : CompositeDrawable { private readonly Slider slider; private readonly ManualSliderBody body; public SliderBodyPiece(Slider slider) - : base(slider) { this.slider = slider; @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components base.Update(); Position = slider.StackedPosition; - body.PathRadius = HitObject.Scale * OsuHitObject.OBJECT_RADIUS; + body.PathRadius = slider.Scale * OsuHitObject.OBJECT_RADIUS; var vertices = new List(); slider.Path.GetPathToProgress(vertices, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index e2084bbb7c..5dab501a24 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -12,14 +12,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { - public class SpinnerPiece : HitObjectPiece + public class SpinnerPiece : CompositeDrawable { private readonly Spinner spinner; private readonly CircularContainer circle; private readonly RingPiece ring; public SpinnerPiece(Spinner spinner) - : base(spinner) { this.spinner = spinner; From bddaead72e5b650b4e2e0205572b3ac232c865bf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 27 Sep 2019 18:45:22 +0900 Subject: [PATCH 03/30] Make hitobject pieces able to update dynamically --- .../Edit/Blueprints/BlueprintPiece.cs | 25 +++++++++++++ .../HitCircles/Components/HitCirclePiece.cs | 18 +++------- .../HitCircles/HitCirclePlacementBlueprint.cs | 11 +++++- .../HitCircles/HitCircleSelectionBlueprint.cs | 13 +++++-- .../Edit/Blueprints/OsuSelectionBlueprint.cs | 7 ++-- .../Components/PathControlPointPiece.cs | 2 +- .../Sliders/Components/SliderBodyPiece.cs | 21 ++++------- .../Sliders/Components/SliderCirclePiece.cs | 35 ------------------- .../Sliders/SliderCircleSelectionBlueprint.cs | 21 ++++++++--- .../Sliders/SliderPlacementBlueprint.cs | 15 ++++++-- .../Sliders/SliderSelectionBlueprint.cs | 16 ++++++--- .../Spinners/Components/SpinnerPiece.cs | 16 +++------ .../Spinners/SpinnerPlacementBlueprint.cs | 9 ++++- .../Spinners/SpinnerSelectionBlueprint.cs | 11 ++++-- 14 files changed, 125 insertions(+), 95 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs delete mode 100644 osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs new file mode 100644 index 0000000000..95e926fdfa --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Blueprints +{ + /// + /// A piece of a selection or placement blueprint which visualises an . + /// + /// The type of which this visualises. + public abstract class BlueprintPiece : CompositeDrawable + where T : OsuHitObject + { + /// + /// Updates this using the properties of a . + /// + /// The to reference properties from. + public virtual void UpdateFrom(T hitObject) + { + Position = hitObject.Position; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index 5e46b3ace4..2b6b93a590 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -11,17 +10,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCirclePiece : CompositeDrawable + public class HitCirclePiece : BlueprintPiece { - private readonly HitCircle hitCircle; - - public HitCirclePiece(HitCircle hitCircle) + public HitCirclePiece() { - this.hitCircle = hitCircle; Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - Scale = new Vector2(hitCircle.Scale); CornerRadius = Size.X / 2; InternalChild = new RingPiece(); @@ -33,14 +28,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components Colour = colours.Yellow; } - protected override void Update() + public override void UpdateFrom(HitCircle hitObject) { - base.Update(); + base.UpdateFrom(hitObject); - UpdatePosition(); - Scale = new Vector2(hitCircle.Scale); + Scale = new Vector2(hitObject.Scale); } - - protected virtual void UpdatePosition() => Position = hitCircle.StackedPosition; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index a4050f0c31..cccef52737 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -13,10 +13,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public new HitCircle HitObject => (HitCircle)base.HitObject; + private readonly HitCirclePiece circlePiece; + public HitCirclePlacementBlueprint() : base(new HitCircle()) { - InternalChild = new HitCirclePiece(HitObject); + InternalChild = circlePiece = new HitCirclePiece(); } protected override void LoadComplete() @@ -27,6 +29,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles HitObject.Position = Parent?.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position) ?? Vector2.Zero; } + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(HitObject); + } + protected override bool OnClick(ClickEvent e) { HitObject.StartTime = EditorClock.CurrentTime; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 83787e2219..430d4a0222 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -7,12 +7,21 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCircleSelectionBlueprint : OsuSelectionBlueprint + public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { + private readonly HitCirclePiece circlePiece; + public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); + InternalChild = circlePiece = new HitCirclePiece(); + } + + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(HitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index dd524252f3..2e4b990db8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -7,11 +7,12 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { - public class OsuSelectionBlueprint : SelectionBlueprint + public abstract class OsuSelectionBlueprint : SelectionBlueprint + where T : OsuHitObject { - protected OsuHitObject OsuObject => (OsuHitObject)HitObject.HitObject; + protected new T HitObject => (T)base.HitObject.HitObject; - public OsuSelectionBlueprint(DrawableHitObject hitObject) + protected OsuSelectionBlueprint(DrawableHitObject hitObject) : base(hitObject) { } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index e257369ad9..3aec7c2872 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointPiece : CompositeDrawable + public class PathControlPointPiece : BlueprintPiece { private readonly Slider slider; private readonly int index; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 239feee431..d28cf7b492 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -12,18 +11,15 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class SliderBodyPiece : CompositeDrawable + public class SliderBodyPiece : BlueprintPiece { - private readonly Slider slider; private readonly ManualSliderBody body; - public SliderBodyPiece(Slider slider) + public SliderBodyPiece() { - this.slider = slider; - InternalChild = body = new ManualSliderBody { - AccentColour = Color4.Transparent, + AccentColour = Color4.Transparent }; } @@ -33,17 +29,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components body.BorderColour = colours.Yellow; } - private void updatePosition() => Position = slider.StackedPosition; - - protected override void Update() + public override void UpdateFrom(Slider hitObject) { - base.Update(); + base.UpdateFrom(hitObject); - Position = slider.StackedPosition; - body.PathRadius = slider.Scale * OsuHitObject.OBJECT_RADIUS; + body.PathRadius = hitObject.Scale * OsuHitObject.OBJECT_RADIUS; var vertices = new List(); - slider.Path.GetPathToProgress(vertices, 0, 1); + hitObject.Path.GetPathToProgress(vertices, 0, 1); body.SetVertices(vertices); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs deleted file mode 100644 index ec3a1d0034..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components -{ - public class SliderCirclePiece : HitCirclePiece - { - private readonly Slider slider; - private readonly SliderPosition position; - - public SliderCirclePiece(Slider slider, SliderPosition position) - : base(slider.HeadCircle) - { - this.slider = slider; - this.position = position; - } - - protected override void UpdatePosition() - { - switch (position) - { - case SliderPosition.Start: - Position = slider.StackedPosition + slider.Path.PositionAt(0); - break; - - case SliderPosition.End: - Position = slider.StackedPosition + slider.Path.PositionAt(1); - break; - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index c9f005495c..8f9a9c3a64 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -1,22 +1,33 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint + public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { - public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) - : base(hitObject) + private readonly SliderPosition position; + private readonly HitCirclePiece circlePiece; + + public SliderCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) + : base(slider) { - InternalChild = new SliderCirclePiece(slider, position); + this.position = position; + InternalChild = circlePiece = new HitCirclePiece(); Select(); } + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle); + } + // Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input. public override bool HandlePositionalInput => false; } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 55de626d7d..4c281a0e7d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osuTK; using osuTK.Input; @@ -21,6 +22,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; + private SliderBodyPiece bodyPiece; + private HitCirclePiece headCirclePiece; + private HitCirclePiece tailCirclePiece; + private readonly List segments = new List(); private Vector2 cursor; @@ -38,9 +43,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { InternalChildren = new Drawable[] { - new SliderBodyPiece(HitObject), - new SliderCirclePiece(HitObject, SliderPosition.Start), - new SliderCirclePiece(HitObject, SliderPosition.End), + bodyPiece = new SliderBodyPiece(), + headCirclePiece = new HitCirclePiece(), + tailCirclePiece = new HitCirclePiece(), new PathControlPointVisualiser(HitObject), }; @@ -130,6 +135,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { var newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); HitObject.Path = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints); + + bodyPiece.UpdateFrom(HitObject); + headCirclePiece.UpdateFrom(HitObject.HeadCircle); + tailCirclePiece.UpdateFrom(HitObject.TailCircle); } private void setState(PlacementState newState) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index fb8c081ff7..bc760c9456 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -9,8 +9,9 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : OsuSelectionBlueprint + public class SliderSelectionBlueprint : OsuSelectionBlueprint { + private readonly SliderBodyPiece bodyPiece; private readonly SliderCircleSelectionBlueprint headBlueprint; public SliderSelectionBlueprint(DrawableSlider slider) @@ -20,13 +21,20 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders InternalChildren = new Drawable[] { - new SliderBodyPiece(sliderObject), - headBlueprint = new SliderCircleSelectionBlueprint(slider.HeadCircle, sliderObject, SliderPosition.Start), - new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), + bodyPiece = new SliderBodyPiece(), + headBlueprint = new SliderCircleSelectionBlueprint(slider, SliderPosition.Start), + new SliderCircleSelectionBlueprint(slider, SliderPosition.End), new PathControlPointVisualiser(sliderObject), }; } + protected override void Update() + { + base.Update(); + + bodyPiece.UpdateFrom(HitObject); + } + public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 5dab501a24..65c8720031 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -12,16 +12,13 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { - public class SpinnerPiece : CompositeDrawable + public class SpinnerPiece : BlueprintPiece { - private readonly Spinner spinner; private readonly CircularContainer circle; private readonly RingPiece ring; - public SpinnerPiece(Spinner spinner) + public SpinnerPiece() { - this.spinner = spinner; - Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; @@ -43,8 +40,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components Origin = Anchor.Centre } }; - - ring.Scale = new Vector2(spinner.Scale); } [BackgroundDependencyLoader] @@ -53,12 +48,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components Colour = colours.Yellow; } - protected override void Update() + public override void UpdateFrom(Spinner hitObject) { - base.Update(); + base.UpdateFrom(hitObject); - Position = spinner.Position; - ring.Scale = new Vector2(spinner.Scale); + ring.Scale = new Vector2(hitObject.Scale); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => circle.ReceivePositionalInputAt(screenSpacePos); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 03d761c67f..8d9dea736b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -21,7 +21,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners public SpinnerPlacementBlueprint() : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { - InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; + InternalChild = piece = new SpinnerPiece { Alpha = 0.5f }; + } + + protected override void Update() + { + base.Update(); + + piece.UpdateFrom(HitObject); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index 25cef3b251..f05d4f8435 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs @@ -8,14 +8,21 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerSelectionBlueprint : OsuSelectionBlueprint + public class SpinnerSelectionBlueprint : OsuSelectionBlueprint { private readonly SpinnerPiece piece; public SpinnerSelectionBlueprint(DrawableSpinner spinner) : base(spinner) { - InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); + InternalChild = piece = new SpinnerPiece(); + } + + protected override void Update() + { + base.Update(); + + piece.UpdateFrom(HitObject); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); From a310c4b65f220afef633a4dc6ff9d8c58c89f0d2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:32:47 +0900 Subject: [PATCH 04/30] Make selection blueprints a bit more testable --- .../TestSceneHoldNoteSelectionBlueprint.cs | 4 ++- .../TestSceneNoteSelectionBlueprint.cs | 8 +++--- .../TestSceneSpinnerSelectionBlueprint.cs | 9 ++++--- .../Visual/SelectionBlueprintTestScene.cs | 26 +++++-------------- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs index 622d840a0c..5507ca2ba0 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs @@ -39,6 +39,8 @@ namespace osu.Game.Rulesets.Mania.Tests AccentColour = { Value = OsuColour.Gray(0.3f) } } }; + + AddBlueprint(new HoldNoteSelectionBlueprint(drawableObject)); } protected override void Update() @@ -52,6 +54,6 @@ namespace osu.Game.Rulesets.Mania.Tests } } - protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs index 6bb344f977..c0482e2150 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs @@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Mania.Tests { public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene { - private readonly DrawableNote drawableObject; - protected override Container Content => content ?? base.Content; private readonly Container content; @@ -27,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.Tests var note = new Note { Column = 0 }; note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + DrawableNote drawableObject; + base.Content.Child = content = new ScrollingTestContainer(ScrollingDirection.Down) { Anchor = Anchor.Centre, @@ -34,8 +34,10 @@ namespace osu.Game.Rulesets.Mania.Tests Size = new Vector2(50, 20), Child = drawableObject = new DrawableNote(note) }; + + AddBlueprint(new NoteSelectionBlueprint(drawableObject)); } - protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs index c5cea76b14..1c195311a4 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs @@ -25,8 +25,6 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(SpinnerPiece) }; - private readonly DrawableSpinner drawableSpinner; - public TestSceneSpinnerSelectionBlueprint() { var spinner = new Spinner @@ -35,16 +33,21 @@ namespace osu.Game.Rulesets.Osu.Tests StartTime = -1000, EndTime = 2000 }; + spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); + DrawableSpinner drawableSpinner; + Add(new Container { RelativeSizeAxes = Axes.Both, Size = new Vector2(0.5f), Child = drawableSpinner = new DrawableSpinner(spinner) }); + + AddBlueprint(new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }); } - protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; + protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(null) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index df3af2cc43..55dda03b16 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -1,10 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; @@ -12,8 +10,6 @@ namespace osu.Game.Tests.Visual { public abstract class SelectionBlueprintTestScene : OsuTestScene { - private SelectionBlueprint blueprint; - protected override Container Content => content ?? base.Content; private readonly Container content; @@ -26,23 +22,13 @@ namespace osu.Game.Tests.Visual }); } - [BackgroundDependencyLoader] - private void load() + protected void AddBlueprint(SelectionBlueprint blueprint) { - blueprint = CreateBlueprint(); - blueprint.Depth = float.MinValue; - blueprint.SelectionRequested += (_, __) => blueprint.Select(); - - Add(blueprint); - - AddStep("Select", () => blueprint.Select()); - AddStep("Deselect", () => blueprint.Deselect()); - } - - protected override bool OnClick(ClickEvent e) - { - blueprint.Deselect(); - return true; + Add(blueprint.With(d => + { + d.Depth = float.MinValue; + d.Select(); + })); } protected abstract SelectionBlueprint CreateBlueprint(); From ba5c9547e14a74af6cee3cbfd61a9066bb944734 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:33:08 +0900 Subject: [PATCH 05/30] Add more tests for hitcircle selection blueprint --- .../TestSceneHitCircleSelectionBlueprint.cs | 45 +++++++++++++++++-- .../HitCircles/HitCircleSelectionBlueprint.cs | 6 +-- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs index 32043bf5d7..7278d923c1 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs @@ -1,10 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -14,16 +16,53 @@ namespace osu.Game.Rulesets.Osu.Tests { public class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene { - private readonly DrawableHitCircle drawableObject; + private HitCircle hitCircle; + private DrawableHitCircle drawableObject; + private TestBlueprint blueprint; - public TestSceneHitCircleSelectionBlueprint() + [SetUp] + public void Setup() => Schedule(() => { - var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; + Clear(); + + hitCircle = new HitCircle { Position = new Vector2(256, 192) }; hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); Add(drawableObject = new DrawableHitCircle(hitCircle)); + AddBlueprint(blueprint = new TestBlueprint(drawableObject)); + }); + + [Test] + public void TestInitialState() + { + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); + } + + [Test] + public void TestMoveHitObject() + { + AddStep("move hitobject", () => hitCircle.Position = new Vector2(300, 225)); + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); + } + + [Test] + public void TestMoveAfterApplyingDefaults() + { + AddStep("apply defaults", () => hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 })); + AddStep("move hitobject", () => hitCircle.Position = new Vector2(300, 225)); + AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); } protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); + + private class TestBlueprint : HitCircleSelectionBlueprint + { + public new HitCirclePiece CirclePiece => base.CirclePiece; + + public TestBlueprint(DrawableHitCircle hitCircle) + : base(hitCircle) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 430d4a0222..a191dba8ff 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -9,19 +9,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { - private readonly HitCirclePiece circlePiece; + protected readonly HitCirclePiece CirclePiece; public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { - InternalChild = circlePiece = new HitCirclePiece(); + InternalChild = CirclePiece = new HitCirclePiece(); } protected override void Update() { base.Update(); - circlePiece.UpdateFrom(HitObject); + CirclePiece.UpdateFrom(HitObject); } } } From 90ad1c5166fdc4dd116ff89554a585c28853774b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:33:24 +0900 Subject: [PATCH 06/30] Add more tests for slider selection blueprint --- .../TestSceneSliderSelectionBlueprint.cs | 79 ++++++++++++++++++- .../Sliders/SliderCircleSelectionBlueprint.cs | 7 +- .../Sliders/SliderSelectionBlueprint.cs | 17 ++-- 3 files changed, 90 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs index 8cf5a2f33e..61c8316ed9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs @@ -3,11 +3,14 @@ using System; using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; @@ -29,11 +32,16 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(PathControlPointPiece) }; - private readonly DrawableSlider drawableObject; + private Slider slider; + private DrawableSlider drawableObject; + private TestSliderBlueprint blueprint; - public TestSceneSliderSelectionBlueprint() + [SetUp] + public void Setup() => Schedule(() => { - var slider = new Slider + Clear(); + + slider = new Slider { Position = new Vector2(256, 192), Path = new SliderPath(PathType.Bezier, new[] @@ -47,8 +55,73 @@ namespace osu.Game.Rulesets.Osu.Tests slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); Add(drawableObject = new DrawableSlider(slider)); + AddBlueprint(blueprint = new TestSliderBlueprint(drawableObject)); + }); + + [Test] + public void TestInitialState() + { + checkPositions(); + } + + [Test] + public void TestMoveHitObject() + { + moveHitObject(); + checkPositions(); + } + + [Test] + public void TestMoveAfterApplyingDefaults() + { + AddStep("apply defaults", () => slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 })); + moveHitObject(); + checkPositions(); + } + + private void moveHitObject() + { + AddStep("move hitobject", () => + { + slider.Position = new Vector2(300, 225); + }); + } + + private void checkPositions() + { + AddAssert("body positioned correctly", () => blueprint.BodyPiece.Position == slider.Position); + + AddAssert("head positioned correctly", + () => Precision.AlmostEquals(blueprint.HeadBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.HeadCircle.ScreenSpaceDrawQuad.Centre)); + + AddAssert("tail positioned correctly", + () => Precision.AlmostEquals(blueprint.TailBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre)); } protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); + + private class TestSliderBlueprint : SliderSelectionBlueprint + { + public new SliderBodyPiece BodyPiece => base.BodyPiece; + public new TestSliderCircleBlueprint HeadBlueprint => (TestSliderCircleBlueprint)base.HeadBlueprint; + public new TestSliderCircleBlueprint TailBlueprint => (TestSliderCircleBlueprint)base.TailBlueprint; + + public TestSliderBlueprint(DrawableSlider slider) + : base(slider) + { + } + + protected override SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new TestSliderCircleBlueprint(slider, position); + } + + private class TestSliderCircleBlueprint : SliderCircleSelectionBlueprint + { + public new HitCirclePiece CirclePiece => base.CirclePiece; + + public TestSliderCircleBlueprint(DrawableSlider slider, SliderPosition position) + : base(slider, position) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index 8f9a9c3a64..f09279ed73 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -9,14 +9,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { + protected readonly HitCirclePiece CirclePiece; + private readonly SliderPosition position; - private readonly HitCirclePiece circlePiece; public SliderCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) : base(slider) { this.position = position; - InternalChild = circlePiece = new HitCirclePiece(); + InternalChild = CirclePiece = new HitCirclePiece(); Select(); } @@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { base.Update(); - circlePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle); + CirclePiece.UpdateFrom(position == SliderPosition.Start ? HitObject.HeadCircle : HitObject.TailCircle); } // Todo: This is temporary, since the slider circle masks don't do anything special yet. In the future they will handle input. diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index bc760c9456..fdeffc6f8a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -11,8 +11,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public class SliderSelectionBlueprint : OsuSelectionBlueprint { - private readonly SliderBodyPiece bodyPiece; - private readonly SliderCircleSelectionBlueprint headBlueprint; + protected readonly SliderBodyPiece BodyPiece; + protected readonly SliderCircleSelectionBlueprint HeadBlueprint; + protected readonly SliderCircleSelectionBlueprint TailBlueprint; public SliderSelectionBlueprint(DrawableSlider slider) : base(slider) @@ -21,9 +22,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders InternalChildren = new Drawable[] { - bodyPiece = new SliderBodyPiece(), - headBlueprint = new SliderCircleSelectionBlueprint(slider, SliderPosition.Start), - new SliderCircleSelectionBlueprint(slider, SliderPosition.End), + BodyPiece = new SliderBodyPiece(), + HeadBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.Start), + TailBlueprint = CreateCircleSelectionBlueprint(slider, SliderPosition.End), new PathControlPointVisualiser(sliderObject), }; } @@ -32,9 +33,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { base.Update(); - bodyPiece.UpdateFrom(HitObject); + BodyPiece.UpdateFrom(HitObject); } - public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; + public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint; + + protected virtual SliderCircleSelectionBlueprint CreateCircleSelectionBlueprint(DrawableSlider slider, SliderPosition position) => new SliderCircleSelectionBlueprint(slider, position); } } From c5540048ab1608873b6377f2fa15bbd4b5b7ab01 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 1 Oct 2019 19:39:06 +0900 Subject: [PATCH 07/30] Fix tail circle not moving with slider position changes --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index d8514092bc..3ed1f2cdde 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -54,13 +54,13 @@ namespace osu.Game.Rulesets.Osu.Objects { base.Position = value; + endPositionCache.Invalidate(); + if (HeadCircle != null) HeadCircle.Position = value; if (TailCircle != null) TailCircle.Position = EndPosition; - - endPositionCache.Invalidate(); } } From 2d0c52239893526a28be0e01eacf74b18bab0ee3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 3 Oct 2019 18:43:46 +0900 Subject: [PATCH 08/30] Remove unused method --- .../TestSceneHoldNoteSelectionBlueprint.cs | 3 --- .../TestSceneNoteSelectionBlueprint.cs | 3 --- .../TestSceneHitCircleSelectionBlueprint.cs | 3 --- .../TestSceneSliderSelectionBlueprint.cs | 3 --- .../TestSceneSpinnerSelectionBlueprint.cs | 3 --- osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs | 2 -- 6 files changed, 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs index 5507ca2ba0..90394f3d1b 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteSelectionBlueprint.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -53,7 +52,5 @@ namespace osu.Game.Rulesets.Mania.Tests nested.Y = (float)(-finalPosition * content.DrawHeight); } } - - protected override SelectionBlueprint CreateBlueprint() => new HoldNoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs index c0482e2150..1514bdf0bd 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNoteSelectionBlueprint.cs @@ -5,7 +5,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -37,7 +36,5 @@ namespace osu.Game.Rulesets.Mania.Tests AddBlueprint(new NoteSelectionBlueprint(drawableObject)); } - - protected override SelectionBlueprint CreateBlueprint() => new NoteSelectionBlueprint(null); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs index 7278d923c1..d4cdabdb07 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleSelectionBlueprint.cs @@ -4,7 +4,6 @@ using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; @@ -53,8 +52,6 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.Position); } - protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); - private class TestBlueprint : HitCircleSelectionBlueprint { public new HitCirclePiece CirclePiece => base.CirclePiece; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs index 61c8316ed9..ec23ec31b2 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs @@ -7,7 +7,6 @@ using NUnit.Framework; using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; @@ -98,8 +97,6 @@ namespace osu.Game.Rulesets.Osu.Tests () => Precision.AlmostEquals(blueprint.TailBlueprint.CirclePiece.ScreenSpaceDrawQuad.Centre, drawableObject.TailCircle.ScreenSpaceDrawQuad.Centre)); } - protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); - private class TestSliderBlueprint : SliderSelectionBlueprint { public new SliderBodyPiece BodyPiece => base.BodyPiece; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs index 1c195311a4..d777ca3610 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerSelectionBlueprint.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; @@ -47,7 +46,5 @@ namespace osu.Game.Rulesets.Osu.Tests AddBlueprint(new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }); } - - protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(null) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index 55dda03b16..f53c12b047 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -30,7 +30,5 @@ namespace osu.Game.Tests.Visual d.Select(); })); } - - protected abstract SelectionBlueprint CreateBlueprint(); } } From e265beb289a3d1df5c5d0645526884e85c410ac9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 7 Oct 2019 18:49:59 +0900 Subject: [PATCH 09/30] Fix merge error --- .../Blueprints/HitCircles/HitCirclePlacementBlueprint.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index 38584ce898..6c08990ad6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -21,6 +21,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles InternalChild = circlePiece = new HitCirclePiece(); } + protected override void Update() + { + base.Update(); + + circlePiece.UpdateFrom(HitObject); + } + protected override bool OnClick(ClickEvent e) { HitObject.StartTime = EditorClock.CurrentTime; From 3ec78388e896e6b5bf1fe1f2fa3869545c6759c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 11:02:54 +0900 Subject: [PATCH 10/30] Avoid excess background updates in playlist overlay --- osu.Game/Overlays/Music/PlaylistList.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 5b528c5ab2..e8c2537c43 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -84,7 +84,7 @@ namespace osu.Game.Overlays.Music beatmaps.ForEach(addBeatmapSet); beatmapBacking.BindTo(beatmap); - beatmapBacking.ValueChanged += _ => updateSelectedSet(); + beatmapBacking.ValueChanged += _ => Scheduler.AddOnce(updateSelectedSet); } private void addBeatmapSet(BeatmapSetInfo obj) From e7fc5e556c79f154b334545b2d367e712c0154e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 10:40:52 +0900 Subject: [PATCH 11/30] Fix song select not correctly playing tracks in some cases --- osu.Game/Screens/Select/SongSelect.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d9ddfa2a94..04a686f481 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -412,9 +412,6 @@ namespace osu.Game.Screens.Select WorkingBeatmap previous = Beatmap.Value; Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous); - if (this.IsCurrentScreen() && Beatmap.Value?.Track != previous?.Track) - ensurePlayingSelected(true); - if (beatmap != null) { if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) @@ -424,6 +421,9 @@ namespace osu.Game.Screens.Select } } + if (this.IsCurrentScreen()) + ensurePlayingSelected(); + UpdateBeatmap(Beatmap.Value); } } @@ -581,19 +581,14 @@ namespace osu.Game.Screens.Select beatmap.Track.Looping = true; } - private void ensurePlayingSelected(bool restart = false) + private void ensurePlayingSelected() { Track track = Beatmap.Value.Track; - if (!track.IsRunning) - { - track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; + track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; - if (restart) - track.Restart(); - else - track.Start(); - } + if (!track.IsRunning) + track.Restart(); } private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); From 5472029ffed6681a327eeacad42577da0306e0e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:27:51 +0900 Subject: [PATCH 12/30] Fix editor defaulting to 0.5x playback speed --- osu.Game/Screens/Edit/Components/PlaybackControl.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 8d4ad0efa9..62d6c4648b 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -105,6 +106,8 @@ namespace osu.Game.Screens.Edit.Components TabContainer.Spacing = Vector2.Zero; tempo_values.ForEach(AddItem); + + Current.Value = tempo_values.Last(); } public class PlaybackTabItem : TabItem From 24269c0384f6ebaa5c09ce52c6a4d404bf23fb7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 12:52:34 +0900 Subject: [PATCH 13/30] Fix skins not being displayed correctly in the editor --- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 13 ++++++++++++- osu.Game/Skinning/SkinProvidingContainer.cs | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index ec4dda5c23..bd7e8e44e5 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Logging; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Skinning; using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose @@ -115,7 +116,17 @@ namespace osu.Game.Screens.Edit.Compose return; } - composerContainer.Child = composer; + var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); + + // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation + // full access to all skin sources. + var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); + + // load the skinning hierarchy first. + // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. + composerContainer.Add( + beatmapSkinProvider.WithChild( + rulesetSkinProvider.WithChild(composer))); } } } diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index ef7f5f381b..1c01bbf1ab 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -53,7 +53,7 @@ namespace osu.Game.Skinning if (AllowTextureLookup(componentName) && (sourceTexture = skin?.GetTexture(componentName)) != null) return sourceTexture; - return fallbackSource.GetTexture(componentName); + return fallbackSource?.GetTexture(componentName); } public SampleChannel GetSample(ISampleInfo sampleInfo) From 63bf8ff832ba04886bb2b60f83247f4b30e3073d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 14:23:13 +0900 Subject: [PATCH 14/30] Better signify under construction screens in editor --- .../Screens/Edit/Compose/ComposeScreen.cs | 41 ++-- osu.Game/Screens/Edit/Design/DesignScreen.cs | 41 +--- osu.Game/Screens/Edit/Editor.cs | 10 + osu.Game/Screens/Edit/Setup/SetupScreen.cs | 13 ++ osu.Game/Screens/Edit/Timing/SetupScreen.cs | 13 ++ osu.Game/Screens/ScreenWhiteBox.cs | 200 ++++++++++-------- 6 files changed, 169 insertions(+), 149 deletions(-) create mode 100644 osu.Game/Screens/Edit/Setup/SetupScreen.cs create mode 100644 osu.Game/Screens/Edit/Timing/SetupScreen.cs diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index bd7e8e44e5..2a99d81516 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; -using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Skinning; @@ -23,8 +22,6 @@ namespace osu.Game.Screens.Edit.Compose private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - private HitObjectComposer composer; - [BackgroundDependencyLoader(true)] private void load([CanBeNull] BindableBeatDivisor beatDivisor) { @@ -107,26 +104,32 @@ namespace osu.Game.Screens.Edit.Compose return; } - composer = ruleset.CreateHitObjectComposer(); + var composer = ruleset.CreateHitObjectComposer(); - if (composer == null) + Drawable content; + + if (composer != null) { - Logger.Log($"Ruleset {ruleset.Description} doesn't support hitobject composition."); - // ExitRequested?.Invoke(); - return; + var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); + + // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation + // full access to all skin sources. + var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); + + // load the skinning hierarchy first. + // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. + content = beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); + } + else + { + content = new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); } - var beatmapSkinProvider = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin); - - // the beatmapSkinProvider is used as the fallback source here to allow the ruleset-specific skin implementation - // full access to all skin sources. - var rulesetSkinProvider = new SkinProvidingContainer(ruleset.CreateLegacySkinProvider(beatmapSkinProvider)); - - // load the skinning hierarchy first. - // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. - composerContainer.Add( - beatmapSkinProvider.WithChild( - rulesetSkinProvider.WithChild(composer))); + LoadComponentAsync(content, _ => + { + composerContainer.Add(content); + content.FadeInFromZero(300, Easing.OutQuint); + }); } } } diff --git a/osu.Game/Screens/Edit/Design/DesignScreen.cs b/osu.Game/Screens/Edit/Design/DesignScreen.cs index 2a334e1b30..9f1fcf55b2 100644 --- a/osu.Game/Screens/Edit/Design/DesignScreen.cs +++ b/osu.Game/Screens/Edit/Design/DesignScreen.cs @@ -1,52 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Sprites; -using osuTK.Graphics; - namespace osu.Game.Screens.Edit.Design { public class DesignScreen : EditorScreen { public DesignScreen() { - Add(new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.35f - }, - new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f - }, - new Container - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding(20), - Child = new OsuSpriteText { Text = "Design screen" } - } - } - } - } - }); + Child = new ScreenWhiteBox.UnderConstructionMessage("Design mode"); } } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 8cc227d9be..9ebe3bc26a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -26,6 +26,8 @@ using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; +using osu.Game.Screens.Edit.Setup; +using osu.Game.Screens.Edit.Timing; using osu.Game.Users; namespace osu.Game.Screens.Edit @@ -258,6 +260,10 @@ namespace osu.Game.Screens.Edit switch (e.NewValue) { + case EditorScreenMode.SongSetup: + currentScreen = new SetupScreen(); + break; + case EditorScreenMode.Compose: currentScreen = new ComposeScreen(); break; @@ -266,6 +272,10 @@ namespace osu.Game.Screens.Edit currentScreen = new DesignScreen(); break; + case EditorScreenMode.Timing: + currentScreen = new TimingScreen(); + break; + default: currentScreen = new EditorScreen(); break; diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs new file mode 100644 index 0000000000..758dbc6e16 --- /dev/null +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Edit.Setup +{ + public class SetupScreen : EditorScreen + { + public SetupScreen() + { + Child = new ScreenWhiteBox.UnderConstructionMessage("Setup mode"); + } + } +} diff --git a/osu.Game/Screens/Edit/Timing/SetupScreen.cs b/osu.Game/Screens/Edit/Timing/SetupScreen.cs new file mode 100644 index 0000000000..9ded4207e5 --- /dev/null +++ b/osu.Game/Screens/Edit/Timing/SetupScreen.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Edit.Timing +{ + public class TimingScreen : EditorScreen + { + public TimingScreen() + { + Child = new ScreenWhiteBox.UnderConstructionMessage("Timing mode"); + } + } +} diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index 6c5854d17e..e4971221c4 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -20,38 +20,17 @@ namespace osu.Game.Screens { public class ScreenWhiteBox : OsuScreen { + private readonly UnderConstructionMessage message; + private const double transition_time = 1000; protected virtual IEnumerable PossibleChildren => null; - private readonly FillFlowContainer textContainer; - private readonly Container boxContainer; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg2"); - public override void OnEntering(IScreen last) - { - base.OnEntering(last); - - Alpha = 0; - textContainer.Position = new Vector2(DrawSize.X / 16, 0); - - boxContainer.ScaleTo(0.2f); - boxContainer.RotateTo(-20); - - using (BeginDelayedSequence(300, true)) - { - boxContainer.ScaleTo(1, transition_time, Easing.OutElastic); - boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint); - - textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); - this.FadeIn(transition_time, Easing.OutExpo); - } - } - public override bool OnExiting(IScreen next) { - textContainer.MoveTo(new Vector2(DrawSize.X / 16, 0), transition_time, Easing.OutExpo); + message.TextContainer.MoveTo(new Vector2(DrawSize.X / 16, 0), transition_time, Easing.OutExpo); this.FadeOut(transition_time, Easing.OutExpo); return base.OnExiting(next); @@ -61,7 +40,7 @@ namespace osu.Game.Screens { base.OnSuspending(next); - textContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, Easing.OutExpo); + message.TextContainer.MoveTo(new Vector2(-(DrawSize.X / 16), 0), transition_time, Easing.OutExpo); this.FadeOut(transition_time, Easing.OutExpo); } @@ -69,7 +48,7 @@ namespace osu.Game.Screens { base.OnResuming(last); - textContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); + message.TextContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); this.FadeIn(transition_time, Easing.OutExpo); } @@ -79,65 +58,7 @@ namespace osu.Game.Screens InternalChildren = new Drawable[] { - boxContainer = new Container - { - Size = new Vector2(0.3f), - RelativeSizeAxes = Axes.Both, - CornerRadius = 20, - Masking = true, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - - Colour = getColourFor(GetType()), - Alpha = 0.2f, - Blending = BlendingParameters.Additive, - }, - textContainer = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.UniversalAccess, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(50), - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = GetType().Name, - Colour = getColourFor(GetType()).Lighten(0.8f), - Font = OsuFont.GetFont(size: 50), - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "is not yet ready for use!", - Font = OsuFont.GetFont(size: 20), - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = "please check back a bit later.", - Font = OsuFont.GetFont(size: 14), - }, - } - }, - } - }, + message = new UnderConstructionMessage(GetType().Name), childModeButtons = new FillFlowContainer { Direction = FillDirection.Vertical, @@ -155,24 +76,24 @@ namespace osu.Game.Screens childModeButtons.Add(new ChildModeButton { Text = $@"{t.Name}", - BackgroundColour = getColourFor(t), - HoverColour = getColourFor(t).Lighten(0.2f), + BackgroundColour = getColourFor(t.Name), + HoverColour = getColourFor(t.Name).Lighten(0.2f), Action = delegate { this.Push(Activator.CreateInstance(t) as Screen); } }); } } } - private Color4 getColourFor(Type type) + private static Color4 getColourFor(object type) { - int hash = type.Name.GetHashCode(); + int hash = type.GetHashCode(); byte r = (byte)MathHelper.Clamp(((hash & 0xFF0000) >> 16) * 0.8f, 20, 255); byte g = (byte)MathHelper.Clamp(((hash & 0x00FF00) >> 8) * 0.8f, 20, 255); byte b = (byte)MathHelper.Clamp((hash & 0x0000FF) * 0.8f, 20, 255); return new Color4(r, g, b, 255); } - public class ChildModeButton : TwoLayerButton + private class ChildModeButton : TwoLayerButton { public ChildModeButton() { @@ -181,5 +102,104 @@ namespace osu.Game.Screens Origin = Anchor.BottomRight; } } + + public class UnderConstructionMessage : CompositeDrawable + { + public FillFlowContainer TextContainer { get; } + + private readonly Container boxContainer; + + public UnderConstructionMessage(string name) + { + RelativeSizeAxes = Axes.Both; + Size = new Vector2(0.3f); + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + var colour = getColourFor(name); + + InternalChildren = new Drawable[] + { + boxContainer = new Container + { + CornerRadius = 20, + Masking = true, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + + Colour = colour, + Alpha = 0.2f, + Blending = BlendingParameters.Additive, + }, + TextContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.UniversalAccess, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(50), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = name, + Colour = colour.Lighten(0.8f), + Font = OsuFont.GetFont(size: 36), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "is not yet ready for use!", + Font = OsuFont.GetFont(size: 20), + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "please check back a bit later.", + Font = OsuFont.GetFont(size: 14), + }, + } + }, + } + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + TextContainer.Position = new Vector2(DrawSize.X / 16, 0); + + boxContainer.Hide(); + boxContainer.ScaleTo(0.2f); + boxContainer.RotateTo(-20); + + using (BeginDelayedSequence(300, true)) + { + boxContainer.ScaleTo(1, transition_time, Easing.OutElastic); + boxContainer.RotateTo(0, transition_time / 2, Easing.OutQuint); + + TextContainer.MoveTo(Vector2.Zero, transition_time, Easing.OutExpo); + boxContainer.FadeIn(transition_time, Easing.OutExpo); + } + } + } } } From 3e904b4838b9169b80b0f6fc2381f0de6a47a6cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 14:37:56 +0900 Subject: [PATCH 15/30] Fix naming of file --- osu.Game/Screens/Edit/Timing/{SetupScreen.cs => TimingScreen.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Screens/Edit/Timing/{SetupScreen.cs => TimingScreen.cs} (100%) diff --git a/osu.Game/Screens/Edit/Timing/SetupScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs similarity index 100% rename from osu.Game/Screens/Edit/Timing/SetupScreen.cs rename to osu.Game/Screens/Edit/Timing/TimingScreen.cs From 4e026b163ccd15556945a8d769cad3b5c0a8ac34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 15:03:48 +0900 Subject: [PATCH 16/30] Don't resume playback when user has paused and track hasn't changed --- osu.Game/Screens/Select/SongSelect.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 04a686f481..6c5f64ed6c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -581,14 +581,24 @@ namespace osu.Game.Screens.Select beatmap.Track.Looping = true; } + private readonly WeakReference lastTrack = new WeakReference(null); + + /// + /// Ensures some music is playing for the current track. + /// Will resume playback from a manual user pause if the track has changed. + /// private void ensurePlayingSelected() { Track track = Beatmap.Value.Track; + bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; + track.RestartPoint = Beatmap.Value.Metadata.PreviewTime; - if (!track.IsRunning) + if (!track.IsRunning && (music?.IsUserPaused != true || isNewTrack)) track.Restart(); + + lastTrack.SetTarget(track); } private void onBeatmapSetAdded(BeatmapSetInfo s) => Carousel.UpdateBeatmapSet(s); From f284d096b75fc63349f08fa0385ce8709e79f214 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 16:37:47 +0900 Subject: [PATCH 17/30] Fix ignored song select test --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 263eada07c..be054495cc 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -128,12 +128,10 @@ namespace osu.Game.Tests.Visual.SongSelect } [Test] - [Ignore("needs fixing")] public void TestImportUnderDifferentRuleset() { createSongSelect(); - changeRuleset(2); - addRulesetImportStep(0); + addRulesetImportStep(2); AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmap == null); } From 8ebccfe31fe098807ed355bf171c990557d6642f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 16:37:34 +0900 Subject: [PATCH 18/30] Add comprehensive audio state tests --- .../SongSelect/TestScenePlaySongSelect.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 263eada07c..5584de5484 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -16,6 +16,7 @@ using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -34,6 +35,8 @@ namespace osu.Game.Tests.Visual.SongSelect private RulesetStore rulesets; + private MusicController music; + private WorkingBeatmap defaultBeatmap; public override IReadOnlyList RequiredTypes => new[] @@ -79,6 +82,11 @@ namespace osu.Game.Tests.Visual.SongSelect Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, host, defaultBeatmap = Beatmap.Default)); + Dependencies.Cache(music = new MusicController()); + + // required to get bindables attached + Add(music); + Beatmap.SetDefault(); Dependencies.Cache(config = new OsuConfigManager(LocalStorage)); @@ -93,6 +101,57 @@ namespace osu.Game.Tests.Visual.SongSelect manager?.Delete(manager.GetAllUsableBeatmapSets()); }); + [Test] + public void TestAudioResuming() + { + createSongSelect(); + + addRulesetImportStep(0); + addRulesetImportStep(0); + + checkMusicPlaying(true); + AddStep("select first", () => songSelect.Carousel.SelectBeatmap(songSelect.Carousel.BeatmapSets.First().Beatmaps.First())); + checkMusicPlaying(true); + + AddStep("manual pause", () => music.TogglePause()); + checkMusicPlaying(false); + AddStep("select next difficulty", () => songSelect.Carousel.SelectNext(skipDifficulties: false)); + checkMusicPlaying(false); + + AddStep("select next set", () => songSelect.Carousel.SelectNext()); + checkMusicPlaying(true); + } + + [TestCase(false)] + [TestCase(true)] + public void TestAudioRemainsCorrectOnRulesetChange(bool rulesetsInSameBeatmap) + { + createSongSelect(); + + // start with non-osu! to avoid convert confusion + changeRuleset(1); + + if (rulesetsInSameBeatmap) + AddStep("import multi-ruleset map", () => + { + var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray(); + manager.Import(createTestBeatmapSet(0, usableRulesets)).Wait(); + }); + else + { + addRulesetImportStep(1); + addRulesetImportStep(0); + } + + checkMusicPlaying(true); + + AddStep("manual pause", () => music.TogglePause()); + checkMusicPlaying(false); + + changeRuleset(0); + checkMusicPlaying(!rulesetsInSameBeatmap); + } + [Test] public void TestDummy() { @@ -224,6 +283,9 @@ namespace osu.Game.Tests.Visual.SongSelect private static int importId; private int getImportId() => ++importId; + private void checkMusicPlaying(bool playing) => + AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing); + private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.Acronym))}", () => Mods.Value = mods); private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id)); From b09d9b7e1f761e9070c0f3aa3629928729c1c7a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 17:56:56 +0900 Subject: [PATCH 19/30] Add todo in slider tail to avoid confusion --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index 23c5494cf5..42bf5e4d21 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables positionBindable.BindValueChanged(_ => updatePosition()); pathBindable.BindValueChanged(_ => updatePosition(), true); + + // TODO: This has no drawable content. Support for skins should be added. } protected override void CheckForResult(bool userTriggered, double timeOffset) From 4446a2972c7c36e48099b99fc597587156cf50c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Oct 2019 18:08:05 +0900 Subject: [PATCH 20/30] Move WaveContainer test out of editor namespace --- .../Visual/{Editor => UserInterface}/TestSceneWaveContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Tests/Visual/{Editor => UserInterface}/TestSceneWaveContainer.cs (97%) diff --git a/osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs similarity index 97% rename from osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs index de19727251..5b130b9224 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneWaveContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; -namespace osu.Game.Tests.Visual.Editor +namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] public class TestSceneWaveContainer : OsuTestScene From 3dd2b18ff0d32cb717bddd6c982e42ca3a7a723f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:04:58 +0900 Subject: [PATCH 21/30] Make EditorScreen abstract --- osu.Game/Screens/Edit/Editor.cs | 6 +----- osu.Game/Screens/Edit/EditorScreen.cs | 15 +++++---------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9ebe3bc26a..7f08c2f8b9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -19,13 +19,13 @@ using osu.Framework.Timing; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components.Menus; -using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Design; using osuTK.Input; using System.Collections.Generic; using osu.Framework; using osu.Framework.Input.Bindings; using osu.Game.Input.Bindings; +using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Edit.Timing; using osu.Game.Users; @@ -275,10 +275,6 @@ namespace osu.Game.Screens.Edit case EditorScreenMode.Timing: currentScreen = new TimingScreen(); break; - - default: - currentScreen = new EditorScreen(); - break; } LoadComponentAsync(currentScreen, screenContainer.Add); diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 045e5a1226..1b57c703ae 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -10,16 +10,17 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Edit { /// - /// TODO: eventually make this inherit Screen and add a local scren stack inside the Editor. + /// TODO: eventually make this inherit Screen and add a local screen stack inside the Editor. /// - public class EditorScreen : Container + public abstract class EditorScreen : Container { - protected readonly IBindable Beatmap = new Bindable(); + [Resolved] + protected IBindable Beatmap { get; private set; } protected override Container Content => content; private readonly Container content; - public EditorScreen() + protected EditorScreen() { Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -28,12 +29,6 @@ namespace osu.Game.Screens.Edit InternalChild = content = new Container { RelativeSizeAxes = Axes.Both }; } - [BackgroundDependencyLoader] - private void load(IBindable beatmap) - { - Beatmap.BindTo(beatmap); - } - protected override void LoadComplete() { base.LoadComplete(); From f2adae8fd167195b667989d30d7bc99b09e12ba3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:05:38 +0900 Subject: [PATCH 22/30] Rename test case to better match underlying class --- ...{TestSceneEditorCompose.cs => TestSceneComposeScreen.cs} | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) rename osu.Game.Tests/Visual/Editor/{TestSceneEditorCompose.cs => TestSceneComposeScreen.cs} (72%) diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs similarity index 72% rename from osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs rename to osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs index 608df1965e..9f16e1d781 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneEditorCompose.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Rulesets.Osu; @@ -11,10 +9,8 @@ using osu.Game.Screens.Edit.Compose; namespace osu.Game.Tests.Visual.Editor { [TestFixture] - public class TestSceneEditorCompose : EditorClockTestScene + public class TestSceneComposeScreen : EditorClockTestScene { - public override IReadOnlyList RequiredTypes => new[] { typeof(ComposeScreen) }; - [BackgroundDependencyLoader] private void load() { From 2d8e5615e4970fc1f47a94ed2690d6f2c0cb8a99 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:05:55 +0900 Subject: [PATCH 23/30] Extract timeline and layout logic from ComposeScreen --- .../Screens/Edit/Compose/ComposeScreen.cs | 111 +----------------- .../Screens/Edit/EditorScreenWithTimeline.cs | 107 +++++++++++++++++ 2 files changed, 112 insertions(+), 106 deletions(-) create mode 100644 osu.Game/Screens/Edit/EditorScreenWithTimeline.cs diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 2a99d81516..1d93c6d4a4 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -1,112 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Logging; -using osu.Game.Screens.Edit.Compose.Components; -using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Skinning; -using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose { - public class ComposeScreen : EditorScreen + public class ComposeScreen : EditorScreenWithTimeline { - private const float vertical_margins = 10; - private const float horizontal_margins = 20; - - private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] BindableBeatDivisor beatDivisor) + protected override Drawable CreateMainContent() { - if (beatDivisor != null) - this.beatDivisor.BindTo(beatDivisor); - - Container composerContainer; - - Children = new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - Name = "Timeline", - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.5f) - }, - new Container - { - Name = "Timeline content", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 5 }, - Child = new TimelineArea { RelativeSizeAxes = Axes.Both } - }, - new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } - }, - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 90), - } - }, - } - } - } - }, - new Drawable[] - { - composerContainer = new Container - { - Name = "Composer content", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, - } - } - }, - RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 110) } - }, - }; - var ruleset = Beatmap.Value.BeatmapInfo.Ruleset?.CreateInstance(); - if (ruleset == null) - { - Logger.Log("Beatmap doesn't have a ruleset assigned."); - // ExitRequested?.Invoke(); - return; - } - - var composer = ruleset.CreateHitObjectComposer(); - - Drawable content; + var composer = ruleset?.CreateHitObjectComposer(); if (composer != null) { @@ -118,18 +25,10 @@ namespace osu.Game.Screens.Edit.Compose // load the skinning hierarchy first. // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. - content = beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); - } - else - { - content = new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); + return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); } - LoadComponentAsync(content, _ => - { - composerContainer.Add(content); - content.FadeInFromZero(300, Easing.OutQuint); - }); + return new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); } } } diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs new file mode 100644 index 0000000000..752356e8c4 --- /dev/null +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -0,0 +1,107 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit +{ + public abstract class EditorScreenWithTimeline : EditorScreen + { + private const float vertical_margins = 10; + private const float horizontal_margins = 20; + + private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); + + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] BindableBeatDivisor beatDivisor) + { + if (beatDivisor != null) + this.beatDivisor.BindTo(beatDivisor); + + Container mainContent; + + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + Name = "Timeline", + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.5f) + }, + new Container + { + Name = "Timeline content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 5 }, + Child = CreateTimeline() + }, + new BeatDivisorControl(beatDivisor) { RelativeSizeAxes = Axes.Both } + }, + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 90), + } + }, + } + } + } + }, + new Drawable[] + { + mainContent = new Container + { + Name = "Main content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = horizontal_margins, Vertical = vertical_margins }, + } + } + }, + RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 110) } + }, + }; + + LoadComponentAsync(CreateMainContent(), content => + { + mainContent.Add(content); + content.FadeInFromZero(300, Easing.OutQuint); + }); + } + + protected abstract Drawable CreateMainContent(); + + protected virtual Drawable CreateTimeline() => new TimelineArea { RelativeSizeAxes = Axes.Both }; + } +} From 0681bb9a2b27f063ae0153ca204b25a895334db1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 16:49:10 +0900 Subject: [PATCH 24/30] Fix potential nullref --- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 1d93c6d4a4..2e9094ebe6 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Compose return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(ruleset.CreateHitObjectComposer())); } - return new ScreenWhiteBox.UnderConstructionMessage($"{ruleset.Description}'s composer"); + return new ScreenWhiteBox.UnderConstructionMessage(ruleset == null ? "This beatmap" : $"{ruleset.Description}'s composer"); } } } From 93d2c3d7a1c43cb9871f1bcb779b51cddcc086e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:03:20 +0900 Subject: [PATCH 25/30] Warn on incorrect null usage --- osu.sln.DotSettings | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index ed162eed6e..ae08a1666f 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -17,7 +17,8 @@ WARNING WARNING HINT - HINT + + True HINT HINT WARNING @@ -738,6 +739,7 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True True True From 51bf600ea7a830d736a748342bd987e6cc4dc878 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:08:31 +0900 Subject: [PATCH 26/30] Use empty hitwindows instead of null --- .../Objects/CatchHitObject.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- .../Objects/HoldNoteTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- .../Objects/SliderTailCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 2 +- .../Objects/DrumRollTick.cs | 2 +- .../Objects/StrongHitObject.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/SwellTick.cs | 2 +- osu.Game/Rulesets/Objects/HitObject.cs | 6 +--- .../Objects/Legacy/Mania/ConvertHit.cs | 2 +- .../Objects/Legacy/Mania/ConvertHold.cs | 2 +- .../Objects/Legacy/Mania/ConvertSlider.cs | 2 +- .../Objects/Legacy/Mania/ConvertSpinner.cs | 2 +- .../Rulesets/Objects/Legacy/Osu/ConvertHit.cs | 2 +- .../Objects/Legacy/Osu/ConvertSlider.cs | 2 +- .../Objects/Legacy/Osu/ConvertSpinner.cs | 2 +- .../Objects/Legacy/Taiko/ConvertHit.cs | 2 +- .../Objects/Legacy/Taiko/ConvertSlider.cs | 2 +- .../Objects/Legacy/Taiko/ConvertSpinner.cs | 2 +- osu.Game/Rulesets/Scoring/HitWindows.cs | 35 +++++++++++++++++++ osu.Game/Rulesets/UI/DrawableRuleset.cs | 4 +-- osu.Game/Screens/Play/HUD/HitErrorDisplay.cs | 2 +- 27 files changed, 62 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 77d7de989a..e4ad49ea50 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Catch.Objects Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } public enum FruitVisualRepresentation diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 0c82cf7bbc..bdba813eed 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -101,6 +101,6 @@ namespace osu.Game.Rulesets.Mania.Objects public override Judgement CreateJudgement() => new HoldNoteJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs index d0125f8793..ac6697a6dc 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteTick.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Mania.Objects { public override Judgement CreateJudgement() => new HoldNoteTickJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs index a794e57c9e..a277517f9f 100644 --- a/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/RepeatPoint.cs @@ -30,6 +30,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 3ed1f2cdde..9bed123465 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -205,6 +205,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 7e540a577b..14c3369967 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -25,6 +25,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuSliderTailJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs index af7cf5b144..a49f4cef8b 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs @@ -32,6 +32,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 2e7b763966..2441a1449d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -33,6 +33,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override Judgement CreateJudgement() => new OsuJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 4e02c76a8b..8956ca9c19 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -88,6 +88,6 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index c466ca7c8a..8a8be3e38d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -27,6 +27,6 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs index d660149528..72a04698be 100644 --- a/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/StrongHitObject.cs @@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public override Judgement CreateJudgement() => new TaikoStrongJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index f96c033dce..e60984596d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -35,6 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Objects public override Judgement CreateJudgement() => new TaikoSwellJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index 68212e8f12..91f4d3dbe7 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public override Judgement CreateJudgement() => new TaikoSwellTickJudgement(); - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index a99fac09cc..eb8652443f 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -66,7 +66,6 @@ namespace osu.Game.Rulesets.Objects /// /// The hit windows for this . /// - [CanBeNull] public HitWindows HitWindows { get; set; } private readonly List nestedHitObjects = new List(); @@ -113,10 +112,7 @@ namespace osu.Game.Rulesets.Objects nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); foreach (var h in nestedHitObjects) - { - h.HitWindows = HitWindows; h.ApplyDefaults(controlPointInfo, difficulty); - } } protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) @@ -147,7 +143,7 @@ namespace osu.Game.Rulesets.Objects /// This will only be invoked if hasn't been set externally (e.g. from a . /// /// - [CanBeNull] + [NotNull] protected virtual HitWindows CreateHitWindows() => new HitWindows(); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs index 609bdd571a..883ef55df0 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs @@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania { public float X { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs index 350ee3185d..69e6f8379d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania public double Duration => EndTime - StartTime; - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs index e372fbd273..4486c5d906 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs @@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania { public float X { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs index 067377d300..c6d1f1922c 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs @@ -17,6 +17,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania public float X { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs index c9851a0074..e40b5b4505 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs @@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public int ComboOffset { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs index 1c1180702b..a163329d47 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs @@ -22,6 +22,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public int ComboOffset { get; set; } - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs index bc94ea1803..5d96a61633 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu public float Y => Position.Y; - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; public bool NewCombo { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs index 709345170f..efb9810927 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs @@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// internal sealed class ConvertHit : HitObject { - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs index c173b3e11a..b365fd34ae 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs @@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// internal sealed class ConvertSlider : Legacy.ConvertSlider { - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs index 9a35ad2776..840ba51ac2 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko public double Duration => EndTime - StartTime; - protected override HitWindows CreateHitWindows() => null; + protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs index efc4cd9f5c..9e7e594104 100644 --- a/osu.Game/Rulesets/Scoring/HitWindows.cs +++ b/osu.Game/Rulesets/Scoring/HitWindows.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; @@ -30,6 +31,17 @@ namespace osu.Game.Rulesets.Scoring private double meh; private double miss; + /// + /// An empty with only and . + /// No time values are provided (meaning instantaneous hit or miss). + /// + public static HitWindows Empty => new EmptyHitWindows(); + + public HitWindows() + { + Debug.Assert(GetRanges().Length >= 1, $"{nameof(HitWindows)}"); + } + /// /// Retrieves the with the largest hit window that produces a successful hit. /// @@ -168,6 +180,29 @@ namespace osu.Game.Rulesets.Scoring /// Defaults are provided but can be overridden to customise for a ruleset. /// protected virtual DifficultyRange[] GetRanges() => base_ranges; + + public class EmptyHitWindows : HitWindows + { + private static readonly DifficultyRange[] ranges = + { + new DifficultyRange(HitResult.Perfect, 0, 0, 0), + new DifficultyRange(HitResult.Miss, 0, 0, 0), + }; + + public override bool IsHitResultAllowed(HitResult result) + { + switch (result) + { + case HitResult.Great: + case HitResult.Miss: + return true; + } + + return false; + } + + protected override DifficultyRange[] GetRanges() => ranges; + } } public struct DifficultyRange diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index d68b0e94c5..d5b3df27df 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -426,11 +426,11 @@ namespace osu.Game.Rulesets.UI { foreach (var h in Objects) { - if (h.HitWindows != null) + if (h.HitWindows.WindowFor(HitResult.Miss) > 0) return h.HitWindows; foreach (var n in h.NestedHitObjects) - if (n.HitWindows != null) + if (h.HitWindows.WindowFor(HitResult.Miss) > 0) return n.HitWindows; } diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs index 920d11c910..54556f8648 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play.HUD private void onNewJudgement(JudgementResult result) { - if (result.HitObject.HitWindows == null) + if (result.HitObject.HitWindows.WindowFor(HitResult.Miss) == 0) return; foreach (var c in Children) From ad6b8d3e04eccee5eaabf496b7b3df2d77c79659 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:08:55 +0900 Subject: [PATCH 27/30] Add result offset bounding to result itself, rather than just transforms --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f8bc74b2a6..7f3bfd3b5c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { UpdateInitialTransforms(); - var judgementOffset = Math.Min(HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? double.MaxValue, Result?.TimeOffset ?? 0); + var judgementOffset = Result?.TimeOffset ?? 0; using (BeginDelayedSequence(InitialLifetimeOffset + judgementOffset, true)) { @@ -379,7 +379,8 @@ namespace osu.Game.Rulesets.Objects.Drawables // Ensure that the judgement is given a valid time offset, because this may not get set by the caller var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime; - Result.TimeOffset = Time.Current - endTime; + + Result.TimeOffset = Math.Min(HitObject.HitWindows.WindowFor(HitResult.Miss), Time.Current - endTime); switch (Result.Type) { From 9f2a64843291fbe2e8dae6f86f8004559b75991b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:23:37 +0900 Subject: [PATCH 28/30] Add full asserts --- osu.Game/Rulesets/Scoring/HitWindows.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs index 9e7e594104..93e4dfc5fa 100644 --- a/osu.Game/Rulesets/Scoring/HitWindows.cs +++ b/osu.Game/Rulesets/Scoring/HitWindows.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; @@ -39,7 +40,8 @@ namespace osu.Game.Rulesets.Scoring public HitWindows() { - Debug.Assert(GetRanges().Length >= 1, $"{nameof(HitWindows)}"); + Debug.Assert(GetRanges().Any(r => r.Result == HitResult.Miss), $"{nameof(GetRanges)} should always contain {nameof(HitResult.Miss)}"); + Debug.Assert(GetRanges().Any(r => r.Result != HitResult.Miss), $"{nameof(GetRanges)} should always contain at least one result type other than {nameof(HitResult.Miss)}."); } /// From e6f857d0d8db175f6cae7b70df070227fb474387 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:03:20 +0900 Subject: [PATCH 29/30] Revert "Warn on incorrect null usage" This reverts commit 93d2c3d7a1c43cb9871f1bcb779b51cddcc086e9. --- osu.sln.DotSettings | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index ae08a1666f..ed162eed6e 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -17,8 +17,7 @@ WARNING WARNING HINT - - True + HINT HINT HINT WARNING @@ -739,7 +738,6 @@ See the LICENCE file in the repository root for full licence text. <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - True True True From 4e273fc628d2bea152dc93f65e9cdbf144c9c610 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Oct 2019 19:50:05 +0900 Subject: [PATCH 30/30] Return correct allowed value for Perfect Co-Authored-By: Salman Ahmed --- osu.Game/Rulesets/Scoring/HitWindows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/HitWindows.cs b/osu.Game/Rulesets/Scoring/HitWindows.cs index 93e4dfc5fa..39d67f1071 100644 --- a/osu.Game/Rulesets/Scoring/HitWindows.cs +++ b/osu.Game/Rulesets/Scoring/HitWindows.cs @@ -195,7 +195,7 @@ namespace osu.Game.Rulesets.Scoring { switch (result) { - case HitResult.Great: + case HitResult.Perfect: case HitResult.Miss: return true; }