diff --git a/.github/ISSUE_TEMPLATE/bug-issues.md b/.github/ISSUE_TEMPLATE/bug-issues.md new file mode 100644 index 0000000000..8d85c92fec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-issues.md @@ -0,0 +1,14 @@ +--- +name: Bug Report +about: For issues regarding encountered game bugs +--- + + + +**Describe your problem:** + +**Screenshots or videos showing encountered issue:** + +**osu!lazer version:** + +**Logs:** \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/crash-issues.md b/.github/ISSUE_TEMPLATE/crash-issues.md new file mode 100644 index 0000000000..849f042c1f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/crash-issues.md @@ -0,0 +1,16 @@ +--- +name: Crash Report +about: For issues regarding game crashes or permanent freezes +--- + + + +**Describe your problem:** + +**Screenshots or videos showing encountered issue:** + +**osu!lazer version:** + +**Logs:** + +**Computer Specifications:** \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature-request-issues.md b/.github/ISSUE_TEMPLATE/feature-request-issues.md new file mode 100644 index 0000000000..73c4f37a3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-issues.md @@ -0,0 +1,10 @@ +--- +name: Feature Request +about: Let us know what you would like to see in the game! +--- + + + +**Describe the feature:** + +**Proposal designs of the feature:** diff --git a/.github/ISSUE_TEMPLATE/missing-for-live-issues.md b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md new file mode 100644 index 0000000000..ae3cf20a8c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/missing-for-live-issues.md @@ -0,0 +1,10 @@ +--- +name: Missing for Live +about: Let us know the features you need which are available in osu-stable but not lazer +--- + + + +**Describe the feature:** + +**Designs:** diff --git a/.gitignore b/.gitignore index 8f011deabe..f95a04e517 100644 --- a/.gitignore +++ b/.gitignore @@ -252,7 +252,11 @@ paket-files/ .fake/ # JetBrains Rider -.idea/ +.idea/.idea.osu/.idea/*.xml +.idea/.idea.osu/.idea/codeStyles/*.xml +.idea/.idea.osu/.idea/dataSources/*.xml +.idea/.idea.osu/.idea/dictionaries/*.xml +.idea/.idea.osu/*.iml *.sln.iml # CodeRush diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 diff --git a/osu-resources b/osu-resources index c3848d8b1c..651e598b01 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit c3848d8b1c84966abe851d915bcca878415614b4 +Subproject commit 651e598b016b43e31ab1c1b29d5b30c92361b8d9 diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs index cac1356c81..bea64302c3 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestCaseAutoJuiceStream.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; @@ -37,13 +38,11 @@ namespace osu.Game.Rulesets.Catch.Tests beatmap.HitObjects.Add(new JuiceStream { X = 0.5f - width / 2, - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(width * CatchPlayfield.BASE_WIDTH, 0) - }, - PathType = PathType.Linear, - Distance = width * CatchPlayfield.BASE_WIDTH, + }), StartTime = i * 2000, NewCombo = i % 8 == 0 }); diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 326791f506..b76f591239 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index a178748bd5..c3dc9499c2 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -34,10 +34,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { StartTime = obj.StartTime, Samples = obj.Samples, - ControlPoints = curveData.ControlPoints, - PathType = curveData.PathType, - Distance = curveData.Distance, - RepeatSamples = curveData.RepeatSamples, + Path = curveData.Path, + NodeSamples = curveData.NodeSamples, RepeatCount = curveData.RepeatCount, X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH, NewCombo = comboData?.NewCombo ?? false, diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index da581d9619..d8bd3e0edc 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -10,7 +10,6 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; -using OpenTK; namespace osu.Game.Rulesets.Catch.Objects { @@ -138,27 +137,17 @@ namespace osu.Game.Rulesets.Catch.Objects public double Duration => EndTime - StartTime; - public double Distance + private SliderPath path; + + public SliderPath Path { - get { return Path.Distance; } - set { Path.Distance = value; } + get => path; + set => path = value; } - public SliderPath Path { get; } = new SliderPath(); + public double Distance => Path.Distance; - public Vector2[] ControlPoints - { - get { return Path.ControlPoints; } - set { Path.ControlPoints = value; } - } - - public List> RepeatSamples { get; set; } = new List>(); - - public PathType PathType - { - get { return Path.PathType; } - set { Path.PathType = value; } - } + public List> NodeSamples { get; set; } = new List>(); public double? LegacyLastTickOffset { get; set; } } diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index bf75ebbff8..98ad086c66 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 5d8480d969..d86ebc9a09 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -247,7 +247,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.SpanCount(); int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); - return curveData.RepeatSamples[index]; + return curveData.NodeSamples[index]; } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 37a8062d75..635004d2f6 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -470,7 +470,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy double segmentTime = (EndTime - HitObject.StartTime) / spanCount; int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); - return curveData.RepeatSamples[index]; + return curveData.NodeSamples[index]; } /// diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs similarity index 84% rename from osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index a2c01d7a0e..3da2538497 100644 --- a/osu.Game.Rulesets.Mania/Edit/Masks/HoldNoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; using osu.Game.Rulesets.Mania.UI; @@ -13,9 +12,9 @@ using osu.Game.Rulesets.UI.Scrolling; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Mania.Edit.Masks +namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class HoldNoteSelectionMask : SelectionMask + public class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint { public new DrawableHoldNote HitObject => (DrawableHoldNote)base.HitObject; @@ -23,13 +22,13 @@ namespace osu.Game.Rulesets.Mania.Edit.Masks private readonly BodyPiece body; - public HoldNoteSelectionMask(DrawableHoldNote hold) + public HoldNoteSelectionBlueprint(DrawableHoldNote hold) : base(hold) { InternalChildren = new Drawable[] { - new HoldNoteNoteSelectionMask(hold.Head), - new HoldNoteNoteSelectionMask(hold.Tail), + new HoldNoteNoteSelectionBlueprint(hold.Head), + new HoldNoteNoteSelectionBlueprint(hold.Tail), body = new BodyPiece { AccentColour = Color4.Transparent @@ -59,9 +58,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Masks Y -= HitObject.Tail.DrawHeight; } - private class HoldNoteNoteSelectionMask : NoteSelectionMask + private class HoldNoteNoteSelectionBlueprint : NoteSelectionBlueprint { - public HoldNoteNoteSelectionMask(DrawableNote note) + public HoldNoteNoteSelectionBlueprint(DrawableNote note) : base(note) { Select(); diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs new file mode 100644 index 0000000000..474b8c662e --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Drawables; + +namespace osu.Game.Rulesets.Mania.Edit.Blueprints +{ + public class ManiaSelectionBlueprint : SelectionBlueprint + { + public ManiaSelectionBlueprint(DrawableHitObject hitObject) + : base(hitObject) + { + } + + public override void AdjustPosition(DragEvent dragEvent) + { + } + } +} diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs similarity index 82% rename from osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs rename to osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 18f042a483..7c0337dc4e 100644 --- a/osu.Game.Rulesets.Mania/Edit/Masks/NoteSelectionMask.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -3,15 +3,14 @@ using osu.Framework.Allocation; using osu.Game.Graphics; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces; -namespace osu.Game.Rulesets.Mania.Edit.Masks +namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class NoteSelectionMask : SelectionMask + public class NoteSelectionBlueprint : ManiaSelectionBlueprint { - public NoteSelectionMask(DrawableNote note) + public NoteSelectionBlueprint(DrawableNote note) : base(note) { Scale = note.Scale; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index fcacde769b..06d67821a9 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Objects.Drawables; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Rulesets.Mania.Configuration; -using osu.Game.Rulesets.Mania.Edit.Masks; +using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI; @@ -38,17 +38,17 @@ namespace osu.Game.Rulesets.Mania.Edit protected override IReadOnlyList CompositionTools => Array.Empty(); - public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableNote note: - return new NoteSelectionMask(note); + return new NoteSelectionBlueprint(note); case DrawableHoldNote holdNote: - return new HoldNoteSelectionMask(holdNote); + return new HoldNoteSelectionBlueprint(holdNote); } - return base.CreateMaskFor(hitObject); + return base.CreateBlueprintFor(hitObject); } } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs similarity index 69% rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs index be0b94c4c8..313438a337 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCirclePlacementBlueprint.cs @@ -4,16 +4,16 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseHitCirclePlacementMask : HitObjectPlacementMaskTestCase + public class TestCaseHitCirclePlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHitCircle((HitCircle)hitObject); - protected override PlacementMask CreateMask() => new HitCirclePlacementMask(); + protected override PlacementBlueprint CreateBlueprint() => new HitCirclePlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs similarity index 71% rename from osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs index e3d61623bf..9662e0018f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseHitCircleSelectionBlueprint.cs @@ -4,7 +4,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -12,11 +12,11 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseHitCircleSelectionMask : HitObjectSelectionMaskTestCase + public class TestCaseHitCircleSelectionBlueprint : SelectionBlueprintTestCase { private readonly DrawableHitCircle drawableObject; - public TestCaseHitCircleSelectionMask() + public TestCaseHitCircleSelectionBlueprint() { var hitCircle = new HitCircle { Position = new Vector2(256, 192) }; hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); @@ -24,6 +24,6 @@ namespace osu.Game.Rulesets.Osu.Tests Add(drawableObject = new DrawableHitCircle(hitCircle)); } - protected override SelectionMask CreateMask() => new HitCircleSelectionMask(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new HitCircleSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs index 4c0385deda..5b638782fb 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSlider.cs @@ -18,6 +18,7 @@ using System.Linq; using NUnit.Framework; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; @@ -108,15 +109,14 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(239, 176), - ControlPoints = new[] + Path = new SliderPath(PathType.PerfectCurve, new[] { Vector2.Zero, new Vector2(154, 28), new Vector2(52, -34) - }, - Distance = 700, + }, 700), RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats), + NodeSamples = createEmptySamples(repeats), StackHeight = 10 }; @@ -141,14 +141,13 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-(distance / 2), 0), - ControlPoints = new[] + Path = new SliderPath(PathType.PerfectCurve, new[] { Vector2.Zero, new Vector2(distance, 0), - }, - Distance = distance, + }, distance), RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats), + NodeSamples = createEmptySamples(repeats), StackHeight = stackHeight }; @@ -161,15 +160,14 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.PerfectCurve, new[] { Vector2.Zero, new Vector2(200, 200), new Vector2(400, 0) - }, - Distance = 600, + }, 600), RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -181,10 +179,9 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - PathType = PathType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(150, 75), @@ -192,10 +189,9 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(300, -200), new Vector2(400, 0), new Vector2(430, 0) - }, - Distance = 793.4417, + }), RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -207,20 +203,18 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - PathType = PathType.Bezier, StartTime = Time.Current + 1000, Position = new Vector2(-200, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.Bezier, new[] { Vector2.Zero, new Vector2(150, 75), new Vector2(200, 100), new Vector2(300, -200), new Vector2(430, 0) - }, - Distance = 480, + }), RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -232,10 +226,9 @@ namespace osu.Game.Rulesets.Osu.Tests { var slider = new Slider { - PathType = PathType.Linear, StartTime = Time.Current + 1000, Position = new Vector2(0, 0), - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(-200, 0), @@ -243,10 +236,9 @@ namespace osu.Game.Rulesets.Osu.Tests new Vector2(0, -200), new Vector2(-200, -200), new Vector2(0, -200) - }, - Distance = 1000, + }), RepeatCount = repeats, - RepeatSamples = createEmptySamples(repeats) + NodeSamples = createEmptySamples(repeats) }; addSlider(slider, 2, 3); @@ -264,17 +256,15 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000, Position = new Vector2(-100, 0), - PathType = PathType.Catmull, - ControlPoints = new[] + Path = new SliderPath(PathType.Catmull, new[] { Vector2.Zero, new Vector2(50, -50), new Vector2(150, 50), new Vector2(200, 0) - }, - Distance = 300, + }), RepeatCount = repeats, - RepeatSamples = repeatSamples + NodeSamples = repeatSamples }; addSlider(slider, 3, 1); diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs similarity index 70% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs index 889ea0c311..1f693ad9f4 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderPlacementBlueprint.cs @@ -4,16 +4,16 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSliderPlacementMask : HitObjectPlacementMaskTestCase + public class TestCaseSliderPlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSlider((Slider)hitObject); - protected override PlacementMask CreateMask() => new SliderPlacementMask(); + protected override PlacementBlueprint CreateBlueprint() => new SliderPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs similarity index 68% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs index 87e0e1a7ec..cacbcb2cd6 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSliderSelectionBlueprint.cs @@ -6,9 +6,10 @@ using System.Collections.Generic; 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.Masks.SliderMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -16,12 +17,12 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSliderSelectionMask : HitObjectSelectionMaskTestCase + public class TestCaseSliderSelectionBlueprint : SelectionBlueprintTestCase { public override IReadOnlyList RequiredTypes => new[] { - typeof(SliderSelectionMask), - typeof(SliderCircleSelectionMask), + typeof(SliderSelectionBlueprint), + typeof(SliderCircleSelectionBlueprint), typeof(SliderBodyPiece), typeof(SliderCircle), typeof(PathControlPointVisualiser), @@ -30,19 +31,17 @@ namespace osu.Game.Rulesets.Osu.Tests private readonly DrawableSlider drawableObject; - public TestCaseSliderSelectionMask() + public TestCaseSliderSelectionBlueprint() { var slider = new Slider { Position = new Vector2(256, 192), - ControlPoints = new[] + Path = new SliderPath(PathType.Bezier, new[] { Vector2.Zero, new Vector2(150, 150), new Vector2(300, 0) - }, - PathType = PathType.Bezier, - Distance = 350 + }) }; slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = 2 }); @@ -50,6 +49,6 @@ namespace osu.Game.Rulesets.Osu.Tests Add(drawableObject = new DrawableSlider(slider)); } - protected override SelectionMask CreateMask() => new SliderSelectionMask(drawableObject); + protected override SelectionBlueprint CreateBlueprint() => new SliderSelectionBlueprint(drawableObject); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs similarity index 70% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs index c2c7942c57..9a90be2582 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerPlacementBlueprint.cs @@ -4,17 +4,17 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSpinnerPlacementMask : HitObjectPlacementMaskTestCase + public class TestCaseSpinnerPlacementBlueprint : PlacementBlueprintTestCase { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); - protected override PlacementMask CreateMask() => new SpinnerPlacementMask(); + protected override PlacementBlueprint CreateBlueprint() => new SpinnerPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs similarity index 74% rename from osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs rename to osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs index b436ff0e9f..a0cfd4487e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionMask.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestCaseSpinnerSelectionBlueprint.cs @@ -8,8 +8,8 @@ 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.Masks.SpinnerMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Tests.Visual; @@ -17,17 +17,17 @@ using OpenTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestCaseSpinnerSelectionMask : HitObjectSelectionMaskTestCase + public class TestCaseSpinnerSelectionBlueprint : SelectionBlueprintTestCase { public override IReadOnlyList RequiredTypes => new[] { - typeof(SpinnerSelectionMask), + typeof(SpinnerSelectionBlueprint), typeof(SpinnerPiece) }; private readonly DrawableSpinner drawableSpinner; - public TestCaseSpinnerSelectionMask() + public TestCaseSpinnerSelectionBlueprint() { var spinner = new Spinner { @@ -45,6 +45,6 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - protected override SelectionMask CreateMask() => new SpinnerSelectionMask(drawableSpinner) { Size = new Vector2(0.5f) }; + protected override SelectionBlueprint CreateBlueprint() => new SpinnerSelectionBlueprint(drawableSpinner) { Size = new Vector2(0.5f) }; } } diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 23c6150b6a..6117812f45 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 9f432fc31a..4fc4f3edc3 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -35,10 +35,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { StartTime = original.StartTime, Samples = original.Samples, - ControlPoints = curveData.ControlPoints, - PathType = curveData.PathType, - Distance = curveData.Distance, - RepeatSamples = curveData.RepeatSamples, + Path = curveData.Path, + NodeSamples = curveData.NodeSamples, RepeatCount = curveData.RepeatCount, Position = positionData?.Position ?? Vector2.Zero, NewCombo = comboData?.NewCombo ?? false, diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs similarity index 94% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index c11ae096a7..9c33435285 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { public class HitCirclePiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs similarity index 82% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index 0d0acbed7d..eddd399a4a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCirclePlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -3,16 +3,16 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCirclePlacementMask : PlacementMask + public class HitCirclePlacementBlueprint : PlacementBlueprint { public new HitCircle HitObject => (HitCircle)base.HitObject; - public HitCirclePlacementMask() + public HitCirclePlacementBlueprint() : base(new HitCircle()) { InternalChild = new HitCirclePiece(HitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs similarity index 58% rename from osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index da46da92a5..a59dac1834 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/HitCircleMasks/HitCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -1,16 +1,15 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.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.Masks.HitCircleMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCircleSelectionMask : SelectionMask + public class HitCircleSelectionBlueprint : OsuSelectionBlueprint { - public HitCircleSelectionMask(DrawableHitCircle hitCircle) + public HitCircleSelectionBlueprint(DrawableHitCircle hitCircle) : base(hitCircle) { InternalChild = new HitCirclePiece((HitCircle)hitCircle.HitObject); diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs new file mode 100644 index 0000000000..8431d5d5d0 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Edit.Blueprints +{ + public class OsuSelectionBlueprint : SelectionBlueprint + { + protected OsuHitObject OsuObject => (OsuHitObject)HitObject.HitObject; + + public OsuSelectionBlueprint(DrawableHitObject hitObject) + : base(hitObject) + { + } + + public override void AdjustPosition(DragEvent dragEvent) => OsuObject.Position += dragEvent.Delta; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs similarity index 82% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 70156578b4..7100d9443e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -9,10 +8,11 @@ using osu.Framework.Graphics.Lines; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Objects; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class PathControlPointPiece : CompositeDrawable { @@ -55,16 +55,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { base.Update(); - Position = slider.StackedPosition + slider.ControlPoints[index]; + Position = slider.StackedPosition + slider.Path.ControlPoints[index]; marker.Colour = isSegmentSeparator ? colours.Red : colours.Yellow; path.ClearVertices(); - if (index != slider.ControlPoints.Length - 1) + if (index != slider.Path.ControlPoints.Length - 1) { path.AddVertex(Vector2.Zero); - path.AddVertex(slider.ControlPoints[index + 1] - slider.ControlPoints[index]); + path.AddVertex(slider.Path.ControlPoints[index + 1] - slider.Path.ControlPoints[index]); } path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components protected override bool OnDrag(DragEvent e) { - var newControlPoints = slider.ControlPoints.ToArray(); + var newControlPoints = slider.Path.ControlPoints.ToArray(); if (index == 0) { @@ -96,8 +96,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components if (isSegmentSeparatorWithPrevious) newControlPoints[index - 1] = newControlPoints[index]; - slider.ControlPoints = newControlPoints; - slider.Path.Calculate(true); + slider.Path = new SliderPath(slider.Path.Type, newControlPoints); return true; } @@ -106,8 +105,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components private bool isSegmentSeparator => isSegmentSeparatorWithNext || isSegmentSeparatorWithPrevious; - private bool isSegmentSeparatorWithNext => index < slider.ControlPoints.Length - 1 && slider.ControlPoints[index + 1] == slider.ControlPoints[index]; + private bool isSegmentSeparatorWithNext => index < slider.Path.ControlPoints.Length - 1 && slider.Path.ControlPoints[index + 1] == slider.Path.ControlPoints[index]; - private bool isSegmentSeparatorWithPrevious => index > 0 && slider.ControlPoints[index - 1] == slider.ControlPoints[index]; + private bool isSegmentSeparatorWithPrevious => index > 0 && slider.Path.ControlPoints[index - 1] == slider.Path.ControlPoints[index]; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs similarity index 77% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 1d25f8cd39..ab9d81574a 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class PathControlPointVisualiser : CompositeDrawable { @@ -19,15 +19,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components InternalChild = pieces = new Container { RelativeSizeAxes = Axes.Both }; - slider.ControlPointsChanged += _ => updatePathControlPoints(); + slider.PathChanged += _ => updatePathControlPoints(); updatePathControlPoints(); } private void updatePathControlPoints() { - while (slider.ControlPoints.Length > pieces.Count) + while (slider.Path.ControlPoints.Length > pieces.Count) pieces.Add(new PathControlPointPiece(slider, pieces.Count)); - while (slider.ControlPoints.Length < pieces.Count) + while (slider.Path.ControlPoints.Length < pieces.Count) pieces.Remove(pieces[pieces.Count - 1]); } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs similarity index 93% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index 006c256d53..06bc265258 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; using OpenTK.Graphics; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class SliderBodyPiece : CompositeDrawable { @@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components { base.Update(); - slider.Path.Calculate(); - var vertices = new List(); slider.Path.GetPathToProgress(vertices, 0, 1); diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs similarity index 83% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs index 7864429d93..1ee765f5e0 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/Components/SliderCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderCirclePiece.cs @@ -1,10 +1,10 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; using osu.Game.Rulesets.Osu.Objects; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { public class SliderCirclePiece : HitCirclePiece { @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components this.slider = slider; this.position = position; - slider.ControlPointsChanged += _ => UpdatePosition(); + slider.PathChanged += _ => UpdatePosition(); } protected override void UpdatePosition() diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs similarity index 53% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs index a1b3fd545c..4bac9d3556 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderCircleSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs @@ -1,18 +1,22 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderCircleSelectionMask : SelectionMask + public class SliderCircleSelectionBlueprint : OsuSelectionBlueprint { - public SliderCircleSelectionMask(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) + private readonly Slider slider; + + public SliderCircleSelectionBlueprint(DrawableOsuHitObject hitObject, Slider slider, SliderPosition position) : base(hitObject) { + this.slider = slider; + InternalChild = new SliderCirclePiece(slider, position); Select(); @@ -20,5 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks // 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; + + public override void AdjustPosition(DragEvent dragEvent) => slider.Position += dragEvent.Delta; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs similarity index 67% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 12e768d58e..d59cd35f19 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -1,24 +1,23 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Input.Events; -using osu.Framework.MathUtils; 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.Masks.SliderMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using OpenTK; using OpenTK.Input; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderPlacementMask : PlacementMask + public class SliderPlacementBlueprint : PlacementBlueprint { public new Objects.Slider HitObject => (Objects.Slider)base.HitObject; @@ -27,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks private PlacementState state; - public SliderPlacementMask() + public SliderPlacementBlueprint() : base(new Objects.Slider()) { RelativeSizeAxes = Axes.Both; @@ -119,12 +118,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks private void updateSlider() { - for (int i = 0; i < segments.Count; i++) - segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null); - - HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); - HitObject.PathType = HitObject.ControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear; - HitObject.Distance = segments.Sum(s => s.Distance); + var newControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray(); + HitObject.Path = new SliderPath(newControlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, newControlPoints); } private void setState(PlacementState newState) @@ -140,41 +135,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks private class Segment { - public float Distance { get; private set; } - public readonly List ControlPoints = new List(); public Segment(Vector2 offset) { ControlPoints.Add(offset); } - - public void Calculate(Vector2? cursor = null) - { - Span allControlPoints = stackalloc Vector2[ControlPoints.Count + (cursor.HasValue ? 1 : 0)]; - - for (int i = 0; i < ControlPoints.Count; i++) - allControlPoints[i] = ControlPoints[i]; - if (cursor.HasValue) - allControlPoints[allControlPoints.Length - 1] = cursor.Value; - - List result; - - switch (allControlPoints.Length) - { - case 1: - case 2: - result = PathApproximator.ApproximateLinear(allControlPoints); - break; - default: - result = PathApproximator.ApproximateBezier(allControlPoints); - break; - } - - Distance = 0; - for (int i = 0; i < result.Count - 1; i++) - Distance += Vector2.Distance(result[i], result[i + 1]); - } } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPosition.cs similarity index 80% rename from osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPosition.cs index 01c1871131..a117a7056e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderPosition.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPosition.cs @@ -1,7 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { public enum SliderPosition { diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs new file mode 100644 index 0000000000..4810d76bf8 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders +{ + public class SliderSelectionBlueprint : OsuSelectionBlueprint + { + private readonly SliderCircleSelectionBlueprint headBlueprint; + + public SliderSelectionBlueprint(DrawableSlider slider) + : base(slider) + { + var sliderObject = (Slider)slider.HitObject; + + InternalChildren = new Drawable[] + { + new SliderBodyPiece(sliderObject), + headBlueprint = new SliderCircleSelectionBlueprint(slider.HeadCircle, sliderObject, SliderPosition.Start), + new SliderCircleSelectionBlueprint(slider.TailCircle, sliderObject, SliderPosition.End), + new PathControlPointVisualiser(sliderObject), + }; + } + + public override Vector2 SelectionPoint => headBlueprint.SelectionPoint; + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs similarity index 96% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 0d9609facf..bd63a3e607 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { public class SpinnerPiece : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs similarity index 82% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index cd5d6cff04..c97adde427 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerPlacementMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -4,13 +4,13 @@ using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerPlacementMask : PlacementMask + public class SpinnerPlacementBlueprint : PlacementBlueprint { public new Spinner HitObject => (Spinner)base.HitObject; @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks private bool isPlacingEnd; - public SpinnerPlacementMask() + public SpinnerPlacementBlueprint() : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { InternalChild = piece = new SpinnerPiece(HitObject) { Alpha = 0.5f }; diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs similarity index 56% rename from osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs rename to osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index 0e47bd2a8b..9e9cc87c5e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SpinnerMasks/SpinnerSelectionMask.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs @@ -1,24 +1,29 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks.Components; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using OpenTK; -namespace osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks +namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerSelectionMask : SelectionMask + public class SpinnerSelectionBlueprint : OsuSelectionBlueprint { private readonly SpinnerPiece piece; - public SpinnerSelectionMask(DrawableSpinner spinner) + public SpinnerSelectionBlueprint(DrawableSpinner spinner) : base(spinner) { InternalChild = piece = new SpinnerPiece((Spinner)spinner.HitObject); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => piece.ReceivePositionalInputAt(screenSpacePos); + + public override void AdjustPosition(DragEvent dragEvent) + { + // Spinners don't support position adjustments + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs index 767c7db5da..ddab70d53a 100644 --- a/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/HitCircleCompositionTool.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementMask CreatePlacementMask() => new HitCirclePlacementMask(); + public override PlacementBlueprint CreatePlacementBlueprint() => new HitCirclePlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs b/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs deleted file mode 100644 index b79b0ba1fb..0000000000 --- a/osu.Game.Rulesets.Osu/Edit/Masks/SliderMasks/SliderSelectionMask.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; -using OpenTK; - -namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks -{ - public class SliderSelectionMask : SelectionMask - { - private readonly SliderCircleSelectionMask headMask; - - public SliderSelectionMask(DrawableSlider slider) - : base(slider) - { - var sliderObject = (Slider)slider.HitObject; - - InternalChildren = new Drawable[] - { - new SliderBodyPiece(sliderObject), - headMask = new SliderCircleSelectionMask(slider.HeadCircle, sliderObject, SliderPosition.Start), - new SliderCircleSelectionMask(slider.TailCircle, sliderObject, SliderPosition.End), - new PathControlPointVisualiser(sliderObject), - }; - } - - public override Vector2 SelectionPoint => headMask.SelectionPoint; - } -} diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 005ccec151..a706e1d4be 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -8,9 +8,9 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -37,19 +37,19 @@ namespace osu.Game.Rulesets.Osu.Edit protected override Container CreateLayerContainer() => new PlayfieldAdjustmentContainer { RelativeSizeAxes = Axes.Both }; - public override SelectionMask CreateMaskFor(DrawableHitObject hitObject) + public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) { switch (hitObject) { case DrawableHitCircle circle: - return new HitCircleSelectionMask(circle); + return new HitCircleSelectionBlueprint(circle); case DrawableSlider slider: - return new SliderSelectionMask(slider); + return new SliderSelectionBlueprint(slider); case DrawableSpinner spinner: - return new SpinnerSelectionMask(spinner); + return new SpinnerSelectionBlueprint(spinner); } - return base.CreateMaskFor(hitObject); + return base.CreateBlueprintFor(hitObject); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs index fd0430ce4c..6d4f67c597 100644 --- a/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SliderCompositionTool.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementMask CreatePlacementMask() => new SliderPlacementMask(); + public override PlacementBlueprint CreatePlacementBlueprint() => new SliderPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs index a1419fe281..5c19a1bac0 100644 --- a/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs +++ b/osu.Game.Rulesets.Osu/Edit/SpinnerCompositionTool.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Osu.Edit.Masks.SpinnerMasks; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit @@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Osu.Edit { } - public override PlacementMask CreatePlacementMask() => new SpinnerPlacementMask(); + public override PlacementBlueprint CreatePlacementBlueprint() => new SpinnerPlacementBlueprint(); } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index e01d71e1f8..223e4df844 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -32,12 +32,11 @@ namespace osu.Game.Rulesets.Osu.Mods slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - var newControlPoints = new Vector2[slider.ControlPoints.Length]; - for (int i = 0; i < slider.ControlPoints.Length; i++) - newControlPoints[i] = new Vector2(slider.ControlPoints[i].X, -slider.ControlPoints[i].Y); + var newControlPoints = new Vector2[slider.Path.ControlPoints.Length]; + for (int i = 0; i < slider.Path.ControlPoints.Length; i++) + newControlPoints[i] = new Vector2(slider.Path.ControlPoints[i].X, -slider.Path.ControlPoints[i].Y); - slider.ControlPoints = newControlPoints; - slider.Path?.Calculate(); // Recalculate the slider curve + slider.Path = new SliderPath(slider.Path.Type, newControlPoints, slider.Path.ExpectedDistance); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 514ae09064..a90182cecb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Ball.Scale = new Vector2(HitObject.Scale); }; - slider.ControlPointsChanged += _ => Body.Refresh(); + slider.PathChanged += _ => Body.Refresh(); } public override Color4 AccentColour diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 6a836679a2..b933364887 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables this.slider = slider; h.PositionChanged += _ => updatePosition(); - slider.ControlPointsChanged += _ => updatePosition(); + slider.PathChanged += _ => updatePosition(); updatePosition(); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index cc88a6718b..6946a55d8e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AlwaysPresent = true; hitCircle.PositionChanged += _ => updatePosition(); - slider.ControlPointsChanged += _ => updatePosition(); + slider.PathChanged += _ => updatePosition(); updatePosition(); } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 67396c7ae4..61d199a7dc 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -7,11 +7,10 @@ using osu.Game.Rulesets.Objects; using OpenTK; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Edit.Types; namespace osu.Game.Rulesets.Osu.Objects { - public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasEditablePosition + public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition { public const double OBJECT_RADIUS = 64; @@ -100,8 +99,6 @@ namespace osu.Game.Rulesets.Osu.Objects Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2; } - public virtual void OffsetPosition(Vector2 offset) => Position += offset; - protected override HitWindows CreateHitWindows() => new OsuHitWindows(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index b7240991d4..cf57f24b83 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// private const float base_scoring_distance = 100; - public event Action ControlPointsChanged; + public event Action PathChanged; public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; public double Duration => EndTime - StartTime; @@ -52,35 +52,23 @@ namespace osu.Game.Rulesets.Osu.Objects } } - public SliderPath Path { get; } = new SliderPath(); + private SliderPath path; - public Vector2[] ControlPoints + public SliderPath Path { - get => Path.ControlPoints; + get => path; set { - if (Path.ControlPoints == value) - return; - Path.ControlPoints = value; + path = value; - ControlPointsChanged?.Invoke(value); + PathChanged?.Invoke(value); if (TailCircle != null) TailCircle.Position = EndPosition; } } - public PathType PathType - { - get { return Path.PathType; } - set { Path.PathType = value; } - } - - public double Distance - { - get { return Path.Distance; } - set { Path.Distance = value; } - } + public double Distance => Path.Distance; public override Vector2 Position { @@ -111,7 +99,8 @@ namespace osu.Game.Rulesets.Osu.Objects /// internal float LazyTravelDistance; - public List> RepeatSamples { get; set; } = new List>(); + public List> NodeSamples { get; set; } = new List>(); + public int RepeatCount { get; set; } /// @@ -165,17 +154,17 @@ namespace osu.Game.Rulesets.Osu.Objects private void createSliderEnds() { - HeadCircle = new SliderCircle(this) + HeadCircle = new SliderCircle { StartTime = StartTime, Position = Position, - Samples = Samples, + Samples = getNodeSamples(0), SampleControlPoint = SampleControlPoint, IndexInCurrentCombo = IndexInCurrentCombo, ComboIndex = ComboIndex, }; - TailCircle = new SliderTailCircle(this) + TailCircle = new SliderTailCircle { StartTime = EndTime, Position = EndPosition, @@ -249,11 +238,18 @@ namespace osu.Game.Rulesets.Osu.Objects Position = Position + Path.PositionAt(repeat % 2), StackHeight = StackHeight, Scale = Scale, - Samples = new List(RepeatSamples[repeatIndex]) + Samples = getNodeSamples(1 + repeatIndex) }); } } + private List getNodeSamples(int nodeIndex) + { + if (nodeIndex < NodeSamples.Count) + return NodeSamples[nodeIndex]; + return Samples; + } + public override Judgement CreateJudgement() => new OsuJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs index 1bdd16c9df..deda951378 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderCircle.cs @@ -1,19 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; - namespace osu.Game.Rulesets.Osu.Objects { public class SliderCircle : HitCircle { - private readonly Slider slider; - - public SliderCircle(Slider slider) - { - this.slider = slider; - } - - public override void OffsetPosition(Vector2 offset) => slider.OffsetPosition(offset); } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 23616ea005..b567bd8423 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -8,11 +8,6 @@ namespace osu.Game.Rulesets.Osu.Objects { public class SliderTailCircle : SliderCircle { - public SliderTailCircle(Slider slider) - : base(slider) - { - } - public override Judgement CreateJudgement() => new OsuSliderTailJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 1270685ab5..1c60fd4831 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -7,7 +7,6 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; -using OpenTK; namespace osu.Game.Rulesets.Osu.Objects { @@ -32,10 +31,5 @@ namespace osu.Game.Rulesets.Osu.Objects } public override Judgement CreateJudgement() => new OsuJudgement(); - - public override void OffsetPosition(Vector2 offset) - { - // for now we don't want to allow spinners to be moved around. - } } } diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 6ae9a018c5..3ba64398f3 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index c2cde332e8..c4a84f416e 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength) { - List> allSamples = curveData != null ? curveData.RepeatSamples : new List>(new[] { samples }); + List> allSamples = curveData != null ? curveData.NodeSamples : new List>(new[] { samples }); int i = 0; for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index f1ae366ee1..464cfbf5e9 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -14,6 +14,7 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Skinning; @@ -333,5 +334,61 @@ namespace osu.Game.Tests.Beatmaps.Formats SampleInfo getTestableSampleInfo(HitObject hitObject) => hitObject.SampleControlPoint.ApplyTo(hitObject.Samples[0]); } + + [Test] + public void TestDecodeSliderSamples() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + using (var resStream = Resource.OpenResource("slider-samples.osu")) + using (var stream = new StreamReader(resStream)) + { + var hitObjects = decoder.Decode(stream).HitObjects; + + var slider1 = (ConvertSlider)hitObjects[0]; + + Assert.AreEqual(1, slider1.NodeSamples[0].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[0][0].Name); + Assert.AreEqual(1, slider1.NodeSamples[1].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[1][0].Name); + Assert.AreEqual(1, slider1.NodeSamples[2].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider1.NodeSamples[2][0].Name); + + var slider2 = (ConvertSlider)hitObjects[1]; + + Assert.AreEqual(2, slider2.NodeSamples[0].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[0][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[0][1].Name); + Assert.AreEqual(2, slider2.NodeSamples[1].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[1][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[1][1].Name); + Assert.AreEqual(2, slider2.NodeSamples[2].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider2.NodeSamples[2][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider2.NodeSamples[2][1].Name); + + var slider3 = (ConvertSlider)hitObjects[2]; + + Assert.AreEqual(2, slider3.NodeSamples[0].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[0][0].Name); + Assert.AreEqual(SampleInfo.HIT_WHISTLE, slider3.NodeSamples[0][1].Name); + Assert.AreEqual(1, slider3.NodeSamples[1].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[1][0].Name); + Assert.AreEqual(2, slider3.NodeSamples[2].Count); + Assert.AreEqual(SampleInfo.HIT_NORMAL, slider3.NodeSamples[2][0].Name); + Assert.AreEqual(SampleInfo.HIT_CLAP, slider3.NodeSamples[2][1].Name); + } + } + + [Test] + public void TestDecodeHitObjectNullAdditionBank() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + using (var resStream = Resource.OpenResource("hitobject-no-addition-bank.osu")) + using (var stream = new StreamReader(resStream)) + { + var hitObjects = decoder.Decode(stream).HitObjects; + + Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank); + } + } } } diff --git a/osu.Game.Tests/Resources/hitobject-no-addition-bank.osu b/osu.Game.Tests/Resources/hitobject-no-addition-bank.osu new file mode 100644 index 0000000000..43d0b8cc16 --- /dev/null +++ b/osu.Game.Tests/Resources/hitobject-no-addition-bank.osu @@ -0,0 +1,4 @@ +osu file format v14 + +[HitObjects] +444,320,1000,5,2,3:0:1:0: \ No newline at end of file diff --git a/osu.Game.Tests/Resources/slider-samples.osu b/osu.Game.Tests/Resources/slider-samples.osu new file mode 100644 index 0000000000..7759a2e35f --- /dev/null +++ b/osu.Game.Tests/Resources/slider-samples.osu @@ -0,0 +1,23 @@ +osu file format v14 + +[General] +SampleSet: Normal + +[Difficulty] + +SliderMultiplier:1.6 +SliderTickRate:2 + +[TimingPoints] +24735,389.61038961039,4,1,1,25,1,0 + +[HitObjects] +// Unified: Normal, Normal, Normal +168,256,30579,6,0,B|248:320|320:248,2,160 + +// Unified: Normal+Clap, Normal+Clap, Normal+Clap +168,256,32137,6,8,B|248:320|320:248,2,160 + +// Nodal: Normal+Whistle, Normal, Normal+Clap +// Nodal sounds should override the unified clap sound +168,256,33696,6,8,B|248:320|320:248,2,160,2|0|8 \ No newline at end of file diff --git a/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs b/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs index 1effa14e76..6c607acd11 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatDivisorControl.cs @@ -5,7 +5,8 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Compose.Components; using OpenTK; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs index e7bcfbf500..5c53fdfac4 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorCompose.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorCompose.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Compose; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual @@ -14,13 +14,13 @@ namespace osu.Game.Tests.Visual [TestFixture] public class TestCaseEditorCompose : EditorClockTestCase { - public override IReadOnlyList RequiredTypes => new[] { typeof(Compose) }; + public override IReadOnlyList RequiredTypes => new[] { typeof(ComposeScreen) }; [BackgroundDependencyLoader] private void load() { Beatmap.Value = new TestWorkingBeatmap(new OsuRuleset().RulesetInfo); - Child = new Compose(); + Child = new ComposeScreen(); } } } diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs index 09f390ab74..9df36b0bc1 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeRadioButtons.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; +using osu.Game.Screens.Edit.Components.RadioButtons; namespace osu.Game.Tests.Visual { diff --git a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs index 9ad8bf7b92..d2c1127f4c 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorComposeTimeline.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Timing; using osu.Game.Beatmaps; -using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using OpenTK.Graphics; namespace osu.Game.Tests.Visual diff --git a/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs b/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs index cb4438b2ba..eab799011d 100644 --- a/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs +++ b/osu.Game.Tests/Visual/TestCaseEditorMenuBar.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Menus; +using osu.Game.Screens.Edit.Components.Menus; namespace osu.Game.Tests.Visual { diff --git a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs index 61647ffdc5..d894d2738e 100644 --- a/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/TestCaseHitObjectComposer.cs @@ -11,13 +11,14 @@ using OpenTK; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks; -using osu.Game.Rulesets.Osu.Edit.Masks.HitCircleMasks.Components; +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.Screens.Edit.Screens.Compose; -using osu.Game.Screens.Edit.Screens.Compose.Layers; +using osu.Game.Screens.Edit.Compose; +using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual @@ -28,15 +29,15 @@ namespace osu.Game.Tests.Visual { public override IReadOnlyList RequiredTypes => new[] { - typeof(MaskSelection), - typeof(DragLayer), + typeof(SelectionBox), + typeof(DragBox), typeof(HitObjectComposer), typeof(OsuHitObjectComposer), - typeof(HitObjectMaskLayer), + typeof(BlueprintContainer), typeof(NotNullAttribute), typeof(HitCirclePiece), - typeof(HitCircleSelectionMask), - typeof(HitCirclePlacementMask), + typeof(HitCircleSelectionBlueprint), + typeof(HitCirclePlacementBlueprint), }; private HitObjectComposer composer; @@ -53,12 +54,11 @@ namespace osu.Game.Tests.Visual new Slider { Position = new Vector2(128, 256), - ControlPoints = new[] + Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(216, 0), - }, - Distance = 216, + }), Scale = 0.5f, } }, diff --git a/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs b/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs index d41739bfb5..e1470a860e 100644 --- a/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs +++ b/osu.Game.Tests/Visual/TestCaseLabelledTextBox.cs @@ -5,9 +5,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Screens.Edit.Screens.Setup.Components.LabelledComponents; using System; using System.Collections.Generic; +using osu.Game.Screens.Edit.Setup.Components.LabelledComponents; namespace osu.Game.Tests.Visual { diff --git a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs index 8bd1b79a84..3bf809ebde 100644 --- a/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseZoomableScrollContainer.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.MathUtils; using osu.Game.Graphics; using osu.Game.Graphics.Cursor; -using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using osu.Game.Screens.Edit.Compose.Components.Timeline; using OpenTK; using OpenTK.Graphics; diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 520e0b8940..c0f0695ff8 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 13571bda84..932cfe5789 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -16,8 +16,8 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Edit.Screens.Compose.Layers; -using osu.Game.Screens.Edit.Screens.Compose.RadioButtons; +using osu.Game.Screens.Edit.Components.RadioButtons; +using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Edit { @@ -35,8 +35,7 @@ namespace osu.Game.Rulesets.Edit private EditRulesetContainer rulesetContainer; - private HitObjectMaskLayer maskLayer; - private PlacementContainer placementContainer; + private BlueprintContainer blueprintContainer; internal HitObjectComposer(Ruleset ruleset) { @@ -62,14 +61,10 @@ namespace osu.Game.Rulesets.Edit } var layerBelowRuleset = CreateLayerContainer(); - layerBelowRuleset.Child = new BorderLayer { RelativeSizeAxes = Axes.Both }; + layerBelowRuleset.Child = new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }; var layerAboveRuleset = CreateLayerContainer(); - layerAboveRuleset.Children = new Drawable[] - { - maskLayer = new HitObjectMaskLayer(), - placementContainer = new PlacementContainer(), - }; + layerAboveRuleset.Child = blueprintContainer = new BlueprintContainer(); layerContainers.Add(layerBelowRuleset); layerContainers.Add(layerAboveRuleset); @@ -112,8 +107,8 @@ namespace osu.Game.Rulesets.Edit }; toolboxCollection.Items = - CompositionTools.Select(t => new RadioButton(t.Name, () => placementContainer.CurrentTool = t)) - .Prepend(new RadioButton("Select", () => placementContainer.CurrentTool = null)) + CompositionTools.Select(t => new RadioButton(t.Name, () => blueprintContainer.CurrentTool = t)) + .Prepend(new RadioButton("Select", () => blueprintContainer.CurrentTool = null)) .ToList(); toolboxCollection.Items[0].Select(); @@ -146,29 +141,25 @@ namespace osu.Game.Rulesets.Edit /// Adds a to the and visualises it. /// /// The to add. - public void Add(HitObject hitObject) - { - maskLayer.AddMaskFor(rulesetContainer.Add(hitObject)); - placementContainer.Refresh(); - } + public void Add(HitObject hitObject) => blueprintContainer.AddBlueprintFor(rulesetContainer.Add(hitObject)); - public void Remove(HitObject hitObject) => maskLayer.RemoveMaskFor(rulesetContainer.Remove(hitObject)); + public void Remove(HitObject hitObject) => blueprintContainer.RemoveBlueprintFor(rulesetContainer.Remove(hitObject)); internal abstract EditRulesetContainer CreateRulesetContainer(); protected abstract IReadOnlyList CompositionTools { get; } /// - /// Creates a for a specific . + /// Creates a for a specific . /// /// The to create the overlay for. - public virtual SelectionMask CreateMaskFor(DrawableHitObject hitObject) => null; + public virtual SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject) => null; /// - /// Creates a which outlines s + /// Creates a which outlines s /// and handles hitobject pattern adjustments. /// - public virtual MaskSelection CreateMaskSelection() => new MaskSelection(); + public virtual SelectionBox CreateSelectionBox() => new SelectionBox(); /// /// Creates a which provides a layer above or below the . diff --git a/osu.Game/Rulesets/Edit/PlacementMask.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs similarity index 86% rename from osu.Game/Rulesets/Edit/PlacementMask.cs rename to osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 97c6a74c92..b726b683ea 100644 --- a/osu.Game/Rulesets/Edit/PlacementMask.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -10,15 +10,15 @@ using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Compose; using OpenTK; namespace osu.Game.Rulesets.Edit { /// - /// A mask which governs the creation of a new to actualisation. + /// A blueprint which governs the creation of a new to actualisation. /// - public abstract class PlacementMask : CompositeDrawable, IRequireHighFrequencyMousePosition + public abstract class PlacementBlueprint : CompositeDrawable, IRequireHighFrequencyMousePosition { /// /// The that is being placed. @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Edit [Resolved] private IPlacementHandler placementHandler { get; set; } - protected PlacementMask(HitObject hitObject) + protected PlacementBlueprint(HitObject hitObject) { HitObject = hitObject; @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Edit /// /// Signals that the placement of has finished. - /// This will destroy this , and add the to the . + /// This will destroy this , and add the to the . /// protected void EndPlacement() { diff --git a/osu.Game/Rulesets/Edit/SelectionMask.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs similarity index 75% rename from osu.Game/Rulesets/Edit/SelectionMask.cs rename to osu.Game/Rulesets/Edit/SelectionBlueprint.cs index 3b78d5aaf6..db35d47b2b 100644 --- a/osu.Game/Rulesets/Edit/SelectionMask.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -15,33 +15,33 @@ using OpenTK; namespace osu.Game.Rulesets.Edit { /// - /// A mask placed above a adding editing functionality. + /// A blueprint placed above a adding editing functionality. /// - public class SelectionMask : CompositeDrawable, IStateful + public abstract class SelectionBlueprint : CompositeDrawable, IStateful { /// - /// Invoked when this has been selected. + /// Invoked when this has been selected. /// - public event Action Selected; + public event Action Selected; /// - /// Invoked when this has been deselected. + /// Invoked when this has been deselected. /// - public event Action Deselected; + public event Action Deselected; /// - /// Invoked when this has requested selection. + /// Invoked when this has requested selection. /// Will fire even if already selected. Does not actually perform selection. /// - public event Action SelectionRequested; + public event Action SelectionRequested; /// - /// Invoked when this has requested drag. + /// Invoked when this has requested drag. /// - public event Action DragRequested; + public event Action DragRequested; /// - /// The which this applies to. + /// The which this applies to. /// public readonly DrawableHitObject HitObject; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Edit public override bool HandlePositionalInput => ShouldBeAlive; public override bool RemoveWhenNotAlive => false; - public SelectionMask(DrawableHitObject hitObject) + protected SelectionBlueprint(DrawableHitObject hitObject) { HitObject = hitObject; @@ -86,12 +86,12 @@ namespace osu.Game.Rulesets.Edit } /// - /// Selects this , causing it to become visible. + /// Selects this , causing it to become visible. /// public void Select() => State = SelectionState.Selected; /// - /// Deselects this , causing it to become invisible. + /// Deselects this , causing it to become invisible. /// public void Deselect() => State = SelectionState.NotSelected; @@ -130,17 +130,19 @@ namespace osu.Game.Rulesets.Edit protected override bool OnDrag(DragEvent e) { - DragRequested?.Invoke(this, e.Delta, e.CurrentState); + DragRequested?.Invoke(e); return true; } + public abstract void AdjustPosition(DragEvent dragEvent); + /// - /// The screen-space point that causes this to be selected. + /// The screen-space point that causes this to be selected. /// public virtual Vector2 SelectionPoint => HitObject.ScreenSpaceDrawQuad.Centre; /// - /// The screen-space quad that outlines this for selections. + /// The screen-space quad that outlines this for selections. /// public virtual Quad SelectionQuad => HitObject.ScreenSpaceDrawQuad; } diff --git a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs index c5d64e3d4d..1cb3c4c451 100644 --- a/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs +++ b/osu.Game/Rulesets/Edit/Tools/HitObjectCompositionTool.cs @@ -12,6 +12,6 @@ namespace osu.Game.Rulesets.Edit.Tools Name = name; } - public abstract PlacementMask CreatePlacementMask(); + public abstract PlacementBlueprint CreatePlacementBlueprint(); } } diff --git a/osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs b/osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs deleted file mode 100644 index 7107b6c763..0000000000 --- a/osu.Game/Rulesets/Edit/Types/IHasEditablePosition.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Game.Rulesets.Objects.Types; -using OpenTK; - -namespace osu.Game.Rulesets.Edit.Types -{ - public interface IHasEditablePosition : IHasPosition - { - void OffsetPosition(Vector2 offset); - } -} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index bcf84b375f..e9e9d93ed5 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -7,7 +7,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.TypeExtensions; -using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Audio; using osu.Game.Graphics; @@ -167,13 +166,7 @@ namespace osu.Game.Rulesets.Objects.Drawables } } - public override bool UpdateSubTreeMasking(Drawable source, RectangleF maskingBounds) - { - if (!AllJudged) - return false; - - return base.UpdateSubTreeMasking(source, maskingBounds); - } + protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => AllJudged && base.ComputeIsMaskedAway(maskingBounds); protected override void UpdateAfterChildren() { diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index f5613e927f..67a3db7a00 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Newtonsoft.Json; -using osu.Framework.Lists; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Objects /// public HitWindows HitWindows { get; set; } - private readonly SortedList nestedHitObjects = new SortedList(compareObjects); + private readonly List nestedHitObjects = new List(); [JsonIgnore] public IReadOnlyList NestedHitObjects => nestedHitObjects; @@ -74,6 +73,8 @@ namespace osu.Game.Rulesets.Objects CreateNestedHitObjects(); + nestedHitObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); + foreach (var h in nestedHitObjects) { h.HitWindows = HitWindows; @@ -114,7 +115,5 @@ namespace osu.Game.Rulesets.Objects /// /// protected virtual HitWindows CreateHitWindows() => new HitWindows(); - - private static int compareObjects(HitObject first, HitObject second) => first.StartTime.CompareTo(second.StartTime); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 85efdca07b..b167812c1d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; @@ -50,10 +50,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch X = position.X, NewCombo = FirstObject || newCombo, ComboOffset = comboOffset, - ControlPoints = controlPoints, - Distance = length, - PathType = pathType, - RepeatSamples = repeatSamples, + Path = new SliderPath(pathType, controlPoints, length), + NodeSamples = nodeSamples, RepeatCount = repeatCount }; } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 73f70d414f..3cc695447e 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -179,6 +179,9 @@ namespace osu.Game.Rulesets.Objects.Legacy nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); result = CreateSlider(pos, combo, comboOffset, points, length, pathType, repeatCount, nodeSamples); + + // The samples are played when the slider ends, which is the last node + result.Samples = nodeSamples[nodeSamples.Count - 1]; } else if (type.HasFlag(ConvertHitObjectType.Spinner)) { @@ -210,7 +213,9 @@ namespace osu.Game.Rulesets.Objects.Legacy } result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture) + Offset; - result.Samples = convertSoundType(soundType, bankInfo); + + if (result.Samples.Count == 0) + result.Samples = convertSoundType(soundType, bankInfo); FirstObject = false; @@ -240,7 +245,7 @@ namespace osu.Game.Rulesets.Objects.Legacy stringAddBank = null; bankInfo.Normal = stringBank; - bankInfo.Add = stringAddBank; + bankInfo.Add = string.IsNullOrEmpty(stringAddBank) ? stringBank : stringAddBank; if (split.Length > 2) bankInfo.CustomSampleBank = int.Parse(split[2]); @@ -270,9 +275,9 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The slider length. /// The slider curve type. /// The slider repeat count. - /// The samples to be played when the repeat nodes are hit. This includes the head and tail of the slider. + /// The samples to be played when the slider nodes are hit. This includes the head and tail of the slider. /// The hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples); /// /// Creates a legacy Spinner-type hit object. diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 6030bff427..0512a97354 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -3,7 +3,6 @@ using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; -using OpenTK; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -20,13 +19,11 @@ namespace osu.Game.Rulesets.Objects.Legacy /// /// s don't need a curve since they're converted to ruleset-specific hitobjects. /// - public SliderPath Path { get; } = null; - public Vector2[] ControlPoints { get; set; } - public PathType PathType { get; set; } + public SliderPath Path { get; set; } - public double Distance { get; set; } + public double Distance => Path.Distance; - public List> RepeatSamples { get; set; } + public List> NodeSamples { get; set; } public int RepeatCount { get; set; } public double EndTime => StartTime + this.SpanCount() * Distance / Velocity; diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 6f10880aa2..fa5e769d3c 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -26,15 +26,13 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { return new ConvertSlider { X = position.X, - ControlPoints = controlPoints, - Distance = length, - PathType = pathType, - RepeatSamples = repeatSamples, + Path = new SliderPath(pathType, controlPoints, length), + NodeSamples = nodeSamples, RepeatCount = repeatCount }; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 31c200eddc..e21903dc6d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { newCombo |= forceNewCombo; comboOffset += extraComboOffset; @@ -51,10 +51,8 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu Position = position, NewCombo = FirstObject || newCombo, ComboOffset = comboOffset, - ControlPoints = controlPoints, - Distance = Math.Max(0, length), - PathType = pathType, - RepeatSamples = repeatSamples, + Path = new SliderPath(pathType, controlPoints, Math.Max(0, length)), + NodeSamples = nodeSamples, RepeatCount = repeatCount }; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 0a244bb6c6..8e1e01a9fd 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -23,14 +23,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko return new ConvertHit(); } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> repeatSamples) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double length, PathType pathType, int repeatCount, List> nodeSamples) { return new ConvertSlider { - ControlPoints = controlPoints, - Distance = length, - PathType = pathType, - RepeatSamples = repeatSamples, + Path = new SliderPath(pathType, controlPoints, length), + NodeSamples = nodeSamples, RepeatCount = repeatCount }; } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 423cd3b069..74a312698c 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -4,28 +4,140 @@ using System; using System.Collections.Generic; using System.Linq; +using Newtonsoft.Json; using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Types; using OpenTK; namespace osu.Game.Rulesets.Objects { - public class SliderPath + public struct SliderPath : IEquatable { - public double Distance; + /// + /// The user-set distance of the path. If non-null, will match this value, + /// and the path will be shortened/lengthened to match this length. + /// + public readonly double? ExpectedDistance; - public Vector2[] ControlPoints = Array.Empty(); + /// + /// The type of path. + /// + public readonly PathType Type; - public PathType PathType = PathType.PerfectCurve; + [JsonProperty] + private Vector2[] controlPoints; - public Vector2 Offset; + private List calculatedPath; + private List cumulativeLength; - private readonly List calculatedPath = new List(); - private readonly List cumulativeLength = new List(); + private bool isInitialised; + + /// + /// Creates a new . + /// + /// The type of path. + /// The control points of the path. + /// A user-set distance of the path that may be shorter or longer than the true distance between all + /// . The path will be shortened/lengthened to match this length. + /// If null, the path will use the true distance between all . + [JsonConstructor] + public SliderPath(PathType type, Vector2[] controlPoints, double? expectedDistance = null) + { + this = default; + this.controlPoints = controlPoints; + + Type = type; + ExpectedDistance = expectedDistance; + + ensureInitialised(); + } + + /// + /// The control points of the path. + /// + [JsonIgnore] + public ReadOnlySpan ControlPoints + { + get + { + ensureInitialised(); + return controlPoints.AsSpan(); + } + } + + /// + /// The distance of the path after lengthening/shortening to account for . + /// + [JsonIgnore] + public double Distance + { + get + { + ensureInitialised(); + return cumulativeLength.Count == 0 ? 0 : cumulativeLength[cumulativeLength.Count - 1]; + } + } + + /// + /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) + /// to 1 (end of the slider) and stores the generated path in the given list. + /// + /// The list to be filled with the computed path. + /// Start progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). + /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). + public void GetPathToProgress(List path, double p0, double p1) + { + ensureInitialised(); + + double d0 = progressToDistance(p0); + double d1 = progressToDistance(p1); + + path.Clear(); + + int i = 0; + for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) + { + } + + path.Add(interpolateVertices(i, d0)); + + for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i) + path.Add(calculatedPath[i]); + + path.Add(interpolateVertices(i, d1)); + } + + /// + /// Computes the position on the slider at a given progress that ranges from 0 (beginning of the path) + /// to 1 (end of the path). + /// + /// Ranges from 0 (beginning of the path) to 1 (end of the path). + /// + public Vector2 PositionAt(double progress) + { + ensureInitialised(); + + double d = progressToDistance(progress); + return interpolateVertices(indexOfDistance(d), d); + } + + private void ensureInitialised() + { + if (isInitialised) + return; + isInitialised = true; + + controlPoints = controlPoints ?? Array.Empty(); + calculatedPath = new List(); + cumulativeLength = new List(); + + calculatePath(); + calculateCumulativeLength(); + } private List calculateSubpath(ReadOnlySpan subControlPoints) { - switch (PathType) + switch (Type) { case PathType.Linear: return PathApproximator.ApproximateLinear(subControlPoints); @@ -66,7 +178,7 @@ namespace osu.Game.Rulesets.Objects if (i == ControlPoints.Length - 1 || ControlPoints[i] == ControlPoints[i + 1]) { - ReadOnlySpan cpSpan = ControlPoints.AsSpan().Slice(start, end - start); + ReadOnlySpan cpSpan = ControlPoints.Slice(start, end - start); foreach (Vector2 t in calculateSubpath(cpSpan)) if (calculatedPath.Count == 0 || calculatedPath.Last() != t) @@ -77,49 +189,6 @@ namespace osu.Game.Rulesets.Objects } } - private void calculateCumulativeLengthAndTrimPath() - { - double l = 0; - - cumulativeLength.Clear(); - cumulativeLength.Add(l); - - for (int i = 0; i < calculatedPath.Count - 1; ++i) - { - Vector2 diff = calculatedPath[i + 1] - calculatedPath[i]; - double d = diff.Length; - - // Shorten slider paths that are too long compared to what's - // in the .osu file. - if (Distance - l < d) - { - calculatedPath[i + 1] = calculatedPath[i] + diff * (float)((Distance - l) / d); - calculatedPath.RemoveRange(i + 2, calculatedPath.Count - 2 - i); - - l = Distance; - cumulativeLength.Add(l); - break; - } - - l += d; - cumulativeLength.Add(l); - } - - // Lengthen slider paths that are too short compared to what's - // in the .osu file. - if (l < Distance && calculatedPath.Count > 1) - { - Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2]; - double d = diff.Length; - - if (d <= 0) - return; - - calculatedPath[calculatedPath.Count - 1] += diff * (float)((Distance - l) / d); - cumulativeLength[calculatedPath.Count - 1] = Distance; - } - } - private void calculateCumulativeLength() { double l = 0; @@ -132,21 +201,33 @@ namespace osu.Game.Rulesets.Objects Vector2 diff = calculatedPath[i + 1] - calculatedPath[i]; double d = diff.Length; + // Shorted slider paths that are too long compared to the expected distance + if (ExpectedDistance.HasValue && ExpectedDistance - l < d) + { + calculatedPath[i + 1] = calculatedPath[i] + diff * (float)((ExpectedDistance - l) / d); + calculatedPath.RemoveRange(i + 2, calculatedPath.Count - 2 - i); + + l = ExpectedDistance.Value; + cumulativeLength.Add(l); + break; + } + l += d; cumulativeLength.Add(l); } - Distance = l; - } + // Lengthen slider paths that are too short compared to the expected distance + if (ExpectedDistance.HasValue && l < ExpectedDistance && calculatedPath.Count > 1) + { + Vector2 diff = calculatedPath[calculatedPath.Count - 1] - calculatedPath[calculatedPath.Count - 2]; + double d = diff.Length; - public void Calculate(bool updateDistance = false) - { - calculatePath(); + if (d <= 0) + return; - if (!updateDistance) - calculateCumulativeLengthAndTrimPath(); - else - calculateCumulativeLength(); + calculatedPath[calculatedPath.Count - 1] += diff * (float)((ExpectedDistance - l) / d); + cumulativeLength[calculatedPath.Count - 1] = ExpectedDistance.Value; + } } private int indexOfDistance(double d) @@ -169,7 +250,7 @@ namespace osu.Game.Rulesets.Objects if (i <= 0) return calculatedPath.First(); - else if (i >= calculatedPath.Count) + if (i >= calculatedPath.Count) return calculatedPath.Last(); Vector2 p0 = calculatedPath[i - 1]; @@ -186,47 +267,20 @@ namespace osu.Game.Rulesets.Objects return p0 + (p1 - p0) * (float)w; } - /// - /// Computes the slider path until a given progress that ranges from 0 (beginning of the slider) - /// to 1 (end of the slider) and stores the generated path in the given list. - /// - /// The list to be filled with the computed path. - /// Start progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). - /// End progress. Ranges from 0 (beginning of the slider) to 1 (end of the slider). - public void GetPathToProgress(List path, double p0, double p1) + public bool Equals(SliderPath other) { - if (calculatedPath.Count == 0 && ControlPoints.Length > 0) - Calculate(); + if (ControlPoints == null && other.ControlPoints != null) + return false; + if (other.ControlPoints == null && ControlPoints != null) + return false; - double d0 = progressToDistance(p0); - double d1 = progressToDistance(p1); - - path.Clear(); - - int i = 0; - for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) { } - - path.Add(interpolateVertices(i, d0) + Offset); - - for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i) - path.Add(calculatedPath[i] + Offset); - - path.Add(interpolateVertices(i, d1) + Offset); + return ControlPoints.SequenceEqual(other.ControlPoints) && ExpectedDistance.Equals(other.ExpectedDistance) && Type == other.Type; } - /// - /// Computes the position on the slider at a given progress that ranges from 0 (beginning of the path) - /// to 1 (end of the path). - /// - /// Ranges from 0 (beginning of the path) to 1 (end of the path). - /// - public Vector2 PositionAt(double progress) + public override bool Equals(object obj) { - if (calculatedPath.Count == 0 && ControlPoints.Length > 0) - Calculate(); - - double d = progressToDistance(progress); - return interpolateVertices(indexOfDistance(d), d) + Offset; + if (ReferenceEquals(null, obj)) return false; + return obj is SliderPath other && Equals(other); } } } diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs index 2a0d495e94..a097b62851 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs @@ -14,16 +14,6 @@ namespace osu.Game.Rulesets.Objects.Types /// The curve. /// SliderPath Path { get; } - - /// - /// The control points that shape the curve. - /// - Vector2[] ControlPoints { get; } - - /// - /// The type of curve. - /// - PathType PathType { get; } } public static class HasCurveExtensions diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index 7d918ff160..ea8784db47 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -17,9 +17,15 @@ namespace osu.Game.Rulesets.Objects.Types int RepeatCount { get; } /// - /// The samples to be played when each repeat node is hit (0 -> first repeat node, 1 -> second repeat node, etc). + /// The samples to be played when each node of the is hit.
+ /// 0: The first node.
+ /// 1: The first repeat.
+ /// 2: The second repeat.
+ /// ...
+ /// n-1: The last repeat.
+ /// n: The last node. ///
- List> RepeatSamples { get; } + List> NodeSamples { get; } } public static class HasRepeatsExtensions diff --git a/osu.Game/Screens/Edit/Screens/Compose/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/BindableBeatDivisor.cs rename to osu.Game/Screens/Edit/BindableBeatDivisor.cs index b7dce8c96e..3124482c73 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -5,7 +5,7 @@ using System; using System.Linq; using osu.Framework.Configuration; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit { public class BindableBeatDivisor : BindableNumber { diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs similarity index 98% rename from osu.Game/Screens/Edit/Menus/EditorMenuBar.cs rename to osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs index af0a7b6694..4b5c13efbd 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs @@ -2,19 +2,18 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; -using osu.Framework.Configuration; -using osu.Framework.Input.Events; -using osu.Game.Screens.Edit.Screens; -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuBar : OsuMenu { diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs similarity index 92% rename from osu.Game/Screens/Edit/Menus/EditorMenuItem.cs rename to osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 0ef1ad8c6b..1c9253cce7 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs @@ -4,7 +4,7 @@ using System; using osu.Game.Graphics.UserInterface; -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItem : OsuMenuItem { diff --git a/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs similarity index 86% rename from osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs rename to osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs index 91b40a2cfb..17ee88241e 100644 --- a/osu.Game/Screens/Edit/Menus/EditorMenuItemSpacer.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs @@ -1,7 +1,7 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItemSpacer : EditorMenuItem { diff --git a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs b/osu.Game/Screens/Edit/Components/Menus/ScreenSelectionTabControl.cs similarity index 96% rename from osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs rename to osu.Game/Screens/Edit/Components/Menus/ScreenSelectionTabControl.cs index f58e5b39eb..4ff01c0f90 100644 --- a/osu.Game/Screens/Edit/Menus/ScreenSelectionTabControl.cs +++ b/osu.Game/Screens/Edit/Components/Menus/ScreenSelectionTabControl.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -9,10 +8,10 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Screens; using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Menus +namespace osu.Game.Screens.Edit.Components.Menus { public class ScreenSelectionTabControl : OsuTabControl { diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs rename to osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs index 2c7e2043fc..22f8417735 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/DrawableRadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/DrawableRadioButton.cs @@ -2,8 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,8 +12,10 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +namespace osu.Game.Screens.Edit.Components.RadioButtons { public class DrawableRadioButton : TriangleButton { diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButton.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs rename to osu.Game/Screens/Edit/Components/RadioButtons/RadioButton.cs index 09fe34bedc..c671fa71c2 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButton.cs @@ -4,7 +4,7 @@ using System; using osu.Framework.Configuration; -namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +namespace osu.Game.Screens.Edit.Components.RadioButtons { public class RadioButton { diff --git a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs rename to osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs index 7ba16b3d3e..9bb2e11430 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/RadioButtons/RadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/RadioButtonCollection.cs @@ -2,12 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using OpenTK; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.RadioButtons +namespace osu.Game.Screens.Edit.Components.RadioButtons { public class RadioButtonCollection : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index 4b57e1e92d..11e9ecddc6 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -43,17 +44,23 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts return true; } + private ScheduledDelegate scheduledSeek; + /// /// Seeks the to the time closest to a position on the screen relative to the . /// /// The position in screen coordinates. private void seekToPosition(Vector2 screenPosition) { - if (Beatmap.Value == null) - return; + scheduledSeek?.Cancel(); + scheduledSeek = Schedule(() => + { + if (Beatmap.Value == null) + return; - float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); - adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length); + float markerPos = MathHelper.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth); + adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length); + }); } protected override void Update() diff --git a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs similarity index 99% rename from osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs rename to osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index e46be9f7c1..a5a1f590bf 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -19,7 +19,7 @@ using OpenTK; using OpenTK.Graphics; using OpenTK.Input; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit.Compose.Components { public class BeatDivisorControl : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs new file mode 100644 index 0000000000..acbfd1f1d6 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -0,0 +1,191 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Input.Events; +using osu.Framework.Input.States; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Objects.Drawables; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + public class BlueprintContainer : CompositeDrawable + { + private SelectionBlueprintContainer selectionBlueprints; + private Container placementBlueprintContainer; + private SelectionBox selectionBox; + + private IEnumerable selections => selectionBlueprints.Children.Where(c => c.IsAlive); + + [Resolved] + private HitObjectComposer composer { get; set; } + + public BlueprintContainer() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + selectionBox = composer.CreateSelectionBox(); + selectionBox.DeselectAll = deselectAll; + + var dragBox = new DragBox(select); + dragBox.DragEnd += () => selectionBox.UpdateVisibility(); + + InternalChildren = new[] + { + dragBox, + selectionBox, + selectionBlueprints = new SelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }, + placementBlueprintContainer = new Container { RelativeSizeAxes = Axes.Both }, + dragBox.CreateProxy() + }; + + foreach (var obj in composer.HitObjects) + AddBlueprintFor(obj); + } + + private HitObjectCompositionTool currentTool; + + /// + /// The current placement tool. + /// + public HitObjectCompositionTool CurrentTool + { + get => currentTool; + set + { + if (currentTool == value) + return; + currentTool = value; + + refreshTool(); + } + } + + /// + /// Adds a blueprint for a which adds movement support. + /// + /// The to create a blueprint for. + public void AddBlueprintFor(DrawableHitObject hitObject) + { + refreshTool(); + + var blueprint = composer.CreateBlueprintFor(hitObject); + if (blueprint == null) + return; + + blueprint.Selected += onBlueprintSelected; + blueprint.Deselected += onBlueprintDeselected; + blueprint.SelectionRequested += onSelectionRequested; + blueprint.DragRequested += onDragRequested; + + selectionBlueprints.Add(blueprint); + } + + /// + /// Removes a blueprint for a . + /// + /// The for which to remove the blueprint. + public void RemoveBlueprintFor(DrawableHitObject hitObject) + { + var blueprint = selectionBlueprints.Single(m => m.HitObject == hitObject); + if (blueprint == null) + return; + + blueprint.Deselect(); + + blueprint.Selected -= onBlueprintSelected; + blueprint.Deselected -= onBlueprintDeselected; + blueprint.SelectionRequested -= onSelectionRequested; + blueprint.DragRequested -= onDragRequested; + + selectionBlueprints.Remove(blueprint); + } + + protected override bool OnClick(ClickEvent e) + { + deselectAll(); + return true; + } + + /// + /// Refreshes the current placement tool. + /// + private void refreshTool() + { + placementBlueprintContainer.Clear(); + + var blueprint = CurrentTool?.CreatePlacementBlueprint(); + if (blueprint != null) + placementBlueprintContainer.Child = blueprint; + } + + + /// + /// Select all masks in a given rectangle selection area. + /// + /// The rectangle to perform a selection on in screen-space coordinates. + private void select(RectangleF rect) + { + foreach (var blueprint in selections.ToList()) + { + if (blueprint.IsPresent && rect.Contains(blueprint.SelectionPoint)) + blueprint.Select(); + else + blueprint.Deselect(); + } + } + + /// + /// Deselects all selected s. + /// + private void deselectAll() => selections.ToList().ForEach(m => m.Deselect()); + + private void onBlueprintSelected(SelectionBlueprint blueprint) + { + selectionBox.HandleSelected(blueprint); + selectionBlueprints.ChangeChildDepth(blueprint, 1); + } + + private void onBlueprintDeselected(SelectionBlueprint blueprint) + { + selectionBox.HandleDeselected(blueprint); + selectionBlueprints.ChangeChildDepth(blueprint, 0); + } + + private void onSelectionRequested(SelectionBlueprint blueprint, InputState state) => selectionBox.HandleSelectionRequested(blueprint, state); + + private void onDragRequested(DragEvent dragEvent) => selectionBox.HandleDrag(dragEvent); + + private class SelectionBlueprintContainer : Container + { + protected override int Compare(Drawable x, Drawable y) + { + if (!(x is SelectionBlueprint xBlueprint) || !(y is SelectionBlueprint yBlueprint)) + return base.Compare(x, y); + return Compare(xBlueprint, yBlueprint); + } + + public int Compare(SelectionBlueprint x, SelectionBlueprint y) + { + // dpeth is used to denote selected status (we always want selected blueprints to handle input first). + int d = x.Depth.CompareTo(y.Depth); + if (d != 0) + return d; + + // Put earlier hitobjects towards the end of the list, so they handle input first + int i = y.HitObject.HitObject.StartTime.CompareTo(x.HitObject.HitObject.StartTime); + return i == 0 ? CompareReverseChildID(x, y) : i; + } + } + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs similarity index 82% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs rename to osu.Game/Screens/Edit/Compose/Components/DragBox.cs index fdc0dee0ce..1a58f476ac 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/DragLayer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs @@ -8,15 +8,14 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; -using osu.Game.Rulesets.Edit; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Layers +namespace osu.Game.Screens.Edit.Compose.Components { /// - /// A layer that handles and displays drag selection for a collection of s. + /// A box that displays the drag selection and provides selection events for users to handle. /// - public class DragLayer : CompositeDrawable + public class DragBox : CompositeDrawable { private readonly Action performSelection; @@ -28,10 +27,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers private Drawable box; /// - /// Creates a new . + /// Creates a new . /// - /// The selectable s. - public DragLayer(Action performSelection) + /// A delegate that performs drag selection. + public DragBox(Action performSelection) { this.performSelection = performSelection; @@ -47,7 +46,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { Masking = true, BorderColour = Color4.White, - BorderThickness = MaskSelection.BORDER_RADIUS, + BorderThickness = SelectionBox.BORDER_RADIUS, Child = new Box { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorPlayfieldBorder.cs b/osu.Game/Screens/Edit/Compose/Components/EditorPlayfieldBorder.cs new file mode 100644 index 0000000000..4956b7759f --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/EditorPlayfieldBorder.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + /// + /// Provides a border around the playfield. + /// + public class EditorPlayfieldBorder : CompositeDrawable + { + public EditorPlayfieldBorder() + { + RelativeSizeAxes = Axes.Both; + + Masking = true; + BorderColour = Color4.White; + BorderThickness = 2; + + InternalChild = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + }; + } + } +} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs similarity index 62% rename from osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs rename to osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 17b34bfb49..8732672723 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskSelection.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -12,29 +12,28 @@ using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Game.Graphics; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Edit.Types; using OpenTK; using OpenTK.Input; -namespace osu.Game.Screens.Edit.Screens.Compose.Layers +namespace osu.Game.Screens.Edit.Compose.Components { /// - /// A box which surrounds s and provides interactive handles, context menus etc. + /// A box which surrounds s and provides interactive handles, context menus etc. /// - public class MaskSelection : CompositeDrawable + public class SelectionBox : CompositeDrawable { public const float BORDER_RADIUS = 2; - private readonly List selectedMasks; + private readonly List selectedBlueprints; private Drawable outline; [Resolved] private IPlacementHandler placementHandler { get; set; } - public MaskSelection() + public SelectionBox() { - selectedMasks = new List(); + selectedBlueprints = new List(); RelativeSizeAxes = Axes.Both; AlwaysPresent = true; @@ -60,19 +59,12 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #region User Input Handling - public void HandleDrag(SelectionMask m, Vector2 delta, InputState state) + public void HandleDrag(DragEvent dragEvent) { // Todo: Various forms of snapping - foreach (var mask in selectedMasks) - { - switch (mask.HitObject.HitObject) - { - case IHasEditablePosition editablePosition: - editablePosition.OffsetPosition(delta); - break; - } - } + foreach (var blueprint in selectedBlueprints) + blueprint.AdjustPosition(dragEvent); } protected override bool OnKeyDown(KeyDownEvent e) @@ -83,7 +75,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers switch (e.Key) { case Key.Delete: - foreach (var h in selectedMasks.ToList()) + foreach (var h in selectedBlueprints.ToList()) placementHandler.Delete(h.HitObject.HitObject); return true; } @@ -96,49 +88,49 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #region Selection Handling /// - /// Bind an action to deselect all selected masks. + /// Bind an action to deselect all selected blueprints. /// public Action DeselectAll { private get; set; } /// - /// Handle a mask becoming selected. + /// Handle a blueprint becoming selected. /// - /// The mask. - public void HandleSelected(SelectionMask mask) => selectedMasks.Add(mask); + /// The blueprint. + public void HandleSelected(SelectionBlueprint blueprint) => selectedBlueprints.Add(blueprint); /// - /// Handle a mask becoming deselected. + /// Handle a blueprint becoming deselected. /// - /// The mask. - public void HandleDeselected(SelectionMask mask) + /// The blueprint. + public void HandleDeselected(SelectionBlueprint blueprint) { - selectedMasks.Remove(mask); + selectedBlueprints.Remove(blueprint); - // We don't want to update visibility if > 0, since we may be deselecting masks during drag-selection - if (selectedMasks.Count == 0) + // We don't want to update visibility if > 0, since we may be deselecting blueprints during drag-selection + if (selectedBlueprints.Count == 0) UpdateVisibility(); } /// - /// Handle a mask requesting selection. + /// Handle a blueprint requesting selection. /// - /// The mask. - public void HandleSelectionRequested(SelectionMask mask, InputState state) + /// The blueprint. + public void HandleSelectionRequested(SelectionBlueprint blueprint, InputState state) { if (state.Keyboard.ControlPressed) { - if (mask.IsSelected) - mask.Deselect(); + if (blueprint.IsSelected) + blueprint.Deselect(); else - mask.Select(); + blueprint.Select(); } else { - if (mask.IsSelected) + if (blueprint.IsSelected) return; DeselectAll?.Invoke(); - mask.Select(); + blueprint.Select(); } UpdateVisibility(); @@ -147,11 +139,11 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers #endregion /// - /// Updates whether this is visible. + /// Updates whether this is visible. /// internal void UpdateVisibility() { - if (selectedMasks.Count > 0) + if (selectedBlueprints.Count > 0) Show(); else Hide(); @@ -161,7 +153,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers { base.Update(); - if (selectedMasks.Count == 0) + if (selectedBlueprints.Count == 0) return; // Move the rectangle to cover the hitobjects @@ -170,10 +162,10 @@ namespace osu.Game.Screens.Edit.Screens.Compose.Layers bool hasSelection = false; - foreach (var mask in selectedMasks) + foreach (var blueprint in selectedBlueprints) { - topLeft = Vector2.ComponentMin(topLeft, ToLocalSpace(mask.SelectionQuad.TopLeft)); - bottomRight = Vector2.ComponentMax(bottomRight, ToLocalSpace(mask.SelectionQuad.BottomRight)); + topLeft = Vector2.ComponentMin(topLeft, ToLocalSpace(blueprint.SelectionQuad.TopLeft)); + bottomRight = Vector2.ComponentMax(bottomRight, ToLocalSpace(blueprint.SelectionQuad.BottomRight)); } topLeft -= new Vector2(5); diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs index 8e932f307d..b2c6f02058 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/CentreMarker.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class CentreMarker : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index da95564975..0c626f2c54 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -12,7 +12,7 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class Timeline : ZoomableScrollContainer { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index ecf760be8e..5b98140a3b 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -1,14 +1,14 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class TimelineArea : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineButton.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 5928fbaa1b..d481934347 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -2,15 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using OpenTK; -using OpenTK.Graphics; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class TimelineButton : CompositeDrawable { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs similarity index 99% rename from osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs rename to osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index bbba439ca7..8d39f61d89 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -9,7 +9,7 @@ using osu.Framework.Input.Events; using osu.Framework.MathUtils; using OpenTK; -namespace osu.Game.Screens.Edit.Screens.Compose.Timeline +namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class ZoomableScrollContainer : ScrollContainer { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs similarity index 96% rename from osu.Game/Screens/Edit/Screens/Compose/Compose.cs rename to osu.Game/Screens/Edit/Compose/ComposeScreen.cs index ae42942d24..30962d5536 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/Compose.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -3,7 +3,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; -using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,12 +10,14 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; -using osu.Game.Screens.Edit.Screens.Compose.Timeline; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Screens.Edit.Compose.Components.Timeline; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit.Compose { [Cached(Type = typeof(IPlacementHandler))] - public class Compose : EditorScreen, IPlacementHandler + public class ComposeScreen : EditorScreen, IPlacementHandler { private const float vertical_margins = 10; private const float horizontal_margins = 20; diff --git a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs b/osu.Game/Screens/Edit/Compose/IPlacementHandler.cs similarity index 95% rename from osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs rename to osu.Game/Screens/Edit/Compose/IPlacementHandler.cs index cd213c2885..f93b294536 100644 --- a/osu.Game/Screens/Edit/Screens/Compose/IPlacementHandler.cs +++ b/osu.Game/Screens/Edit/Compose/IPlacementHandler.cs @@ -3,7 +3,7 @@ using osu.Game.Rulesets.Objects; -namespace osu.Game.Screens.Edit.Screens.Compose +namespace osu.Game.Screens.Edit.Compose { public interface IPlacementHandler { diff --git a/osu.Game/Screens/Edit/Screens/Design/Design.cs b/osu.Game/Screens/Edit/Design/DesignScreen.cs similarity index 93% rename from osu.Game/Screens/Edit/Screens/Design/Design.cs rename to osu.Game/Screens/Edit/Design/DesignScreen.cs index 052a1c1d90..e99e352653 100644 --- a/osu.Game/Screens/Edit/Screens/Design/Design.cs +++ b/osu.Game/Screens/Edit/Design/DesignScreen.cs @@ -7,11 +7,11 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Design +namespace osu.Game.Screens.Edit.Design { - public class Design : EditorScreen + public class DesignScreen : EditorScreen { - public Design() + public DesignScreen() { Add(new Container { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 62cf76ef69..524f049284 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Screens.Edit.Menus; using osu.Game.Screens.Edit.Components.Timelines.Summary; using osu.Framework.Allocation; using osu.Framework.Graphics.UserInterface; @@ -16,10 +15,10 @@ using osu.Framework.Input.Events; using osu.Framework.Platform; using osu.Framework.Timing; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Edit.Screens; -using osu.Game.Screens.Edit.Screens.Compose; -using osu.Game.Screens.Edit.Screens.Design; 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; namespace osu.Game.Screens.Edit { @@ -169,10 +168,10 @@ namespace osu.Game.Screens.Edit switch (mode) { case EditorScreenMode.Compose: - currentScreen = new Compose(); + currentScreen = new ComposeScreen(); break; case EditorScreenMode.Design: - currentScreen = new Design(); + currentScreen = new DesignScreen(); break; default: currentScreen = new EditorScreen(); diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 1c40181ec9..5fa29d6005 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -7,7 +7,6 @@ using osu.Framework.MathUtils; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Screens.Edit.Screens.Compose; using OpenTK; namespace osu.Game.Screens.Edit diff --git a/osu.Game/Screens/Edit/Screens/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs similarity index 97% rename from osu.Game/Screens/Edit/Screens/EditorScreen.cs rename to osu.Game/Screens/Edit/EditorScreen.cs index f8402b9a9f..3a8fc3ef80 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -namespace osu.Game.Screens.Edit.Screens +namespace osu.Game.Screens.Edit { /// /// TODO: eventually make this inherit Screen and add a local scren stack inside the Editor. diff --git a/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs b/osu.Game/Screens/Edit/EditorScreenMode.cs similarity index 91% rename from osu.Game/Screens/Edit/Screens/EditorScreenMode.cs rename to osu.Game/Screens/Edit/EditorScreenMode.cs index be8363680d..17de6c4125 100644 --- a/osu.Game/Screens/Edit/Screens/EditorScreenMode.cs +++ b/osu.Game/Screens/Edit/EditorScreenMode.cs @@ -3,7 +3,7 @@ using System.ComponentModel; -namespace osu.Game.Screens.Edit.Screens +namespace osu.Game.Screens.Edit { public enum EditorScreenMode { diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs deleted file mode 100644 index c46f9a1b7f..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/BorderLayer.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using OpenTK.Graphics; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class BorderLayer : Container - { - protected override Container Content => content; - private readonly Container content; - - public BorderLayer() - { - InternalChildren = new Drawable[] - { - new Container - { - Name = "Border", - RelativeSizeAxes = Axes.Both, - Masking = true, - BorderColour = Color4.White, - BorderThickness = 2, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - }, - content = new Container { RelativeSizeAxes = Axes.Both } - }; - } - } -} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs deleted file mode 100644 index 0392cb5952..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/HitObjectMaskLayer.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects.Drawables; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class HitObjectMaskLayer : CompositeDrawable - { - private MaskContainer maskContainer; - - [Resolved] - private HitObjectComposer composer { get; set; } - - public HitObjectMaskLayer() - { - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - maskContainer = new MaskContainer(); - - var maskSelection = composer.CreateMaskSelection(); - - maskContainer.MaskSelected += maskSelection.HandleSelected; - maskContainer.MaskDeselected += maskSelection.HandleDeselected; - maskContainer.MaskSelectionRequested += maskSelection.HandleSelectionRequested; - maskContainer.MaskDragRequested += maskSelection.HandleDrag; - - maskSelection.DeselectAll = maskContainer.DeselectAll; - - var dragLayer = new DragLayer(maskContainer.Select); - dragLayer.DragEnd += () => maskSelection.UpdateVisibility(); - - InternalChildren = new[] - { - dragLayer, - maskSelection, - maskContainer, - dragLayer.CreateProxy() - }; - - foreach (var obj in composer.HitObjects) - AddMaskFor(obj); - } - - protected override bool OnClick(ClickEvent e) - { - maskContainer.DeselectAll(); - return true; - } - - /// - /// Adds a mask for a which adds movement support. - /// - /// The to create a mask for. - public void AddMaskFor(DrawableHitObject hitObject) - { - var mask = composer.CreateMaskFor(hitObject); - if (mask == null) - return; - - maskContainer.Add(mask); - } - - /// - /// Removes a mask for a . - /// - /// The for which to remove the mask. - public void RemoveMaskFor(DrawableHitObject hitObject) - { - var maskToRemove = maskContainer.Single(m => m.HitObject == hitObject); - if (maskToRemove == null) - return; - - maskToRemove.Deselect(); - maskContainer.Remove(maskToRemove); - } - } -} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs deleted file mode 100644 index 42a7757721..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/MaskContainer.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.States; -using osu.Game.Rulesets.Edit; -using OpenTK; -using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class MaskContainer : Container - { - /// - /// Invoked when any is selected. - /// - public event Action MaskSelected; - - /// - /// Invoked when any is deselected. - /// - public event Action MaskDeselected; - - /// - /// Invoked when any requests selection. - /// - public event Action MaskSelectionRequested; - - /// - /// Invoked when any requests drag. - /// - public event Action MaskDragRequested; - - private IEnumerable aliveMasks => AliveInternalChildren.Cast(); - - public MaskContainer() - { - RelativeSizeAxes = Axes.Both; - } - - public override void Add(SelectionMask drawable) - { - if (drawable == null) throw new ArgumentNullException(nameof(drawable)); - - base.Add(drawable); - - drawable.Selected += onMaskSelected; - drawable.Deselected += onMaskDeselected; - drawable.SelectionRequested += onSelectionRequested; - drawable.DragRequested += onDragRequested; - } - - public override bool Remove(SelectionMask drawable) - { - if (drawable == null) throw new ArgumentNullException(nameof(drawable)); - - var result = base.Remove(drawable); - - if (result) - { - drawable.Selected -= onMaskSelected; - drawable.Deselected -= onMaskDeselected; - drawable.SelectionRequested -= onSelectionRequested; - drawable.DragRequested -= onDragRequested; - } - - return result; - } - - /// - /// Select all masks in a given rectangle selection area. - /// - /// The rectangle to perform a selection on in screen-space coordinates. - public void Select(RectangleF rect) - { - foreach (var mask in aliveMasks.ToList()) - { - if (mask.IsPresent && rect.Contains(mask.SelectionPoint)) - mask.Select(); - else - mask.Deselect(); - } - } - - /// - /// Deselects all selected s. - /// - public void DeselectAll() => aliveMasks.ToList().ForEach(m => m.Deselect()); - - private void onMaskSelected(SelectionMask mask) - { - MaskSelected?.Invoke(mask); - ChangeChildDepth(mask, 1); - } - - private void onMaskDeselected(SelectionMask mask) - { - MaskDeselected?.Invoke(mask); - ChangeChildDepth(mask, 0); - } - - private void onSelectionRequested(SelectionMask mask, InputState state) => MaskSelectionRequested?.Invoke(mask, state); - private void onDragRequested(SelectionMask mask, Vector2 delta, InputState state) => MaskDragRequested?.Invoke(mask, delta, state); - - protected override int Compare(Drawable x, Drawable y) - { - if (!(x is SelectionMask xMask) || !(y is SelectionMask yMask)) - return base.Compare(x, y); - return Compare(xMask, yMask); - } - - public int Compare(SelectionMask x, SelectionMask y) - { - // dpeth is used to denote selected status (we always want selected masks to handle input first). - int d = x.Depth.CompareTo(y.Depth); - if (d != 0) - return d; - - // Put earlier hitobjects towards the end of the list, so they handle input first - int i = y.HitObject.HitObject.StartTime.CompareTo(x.HitObject.HitObject.StartTime); - return i == 0 ? CompareReverseChildID(x, y) : i; - } - } -} diff --git a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs b/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs deleted file mode 100644 index ea167a5c6b..0000000000 --- a/osu.Game/Screens/Edit/Screens/Compose/Layers/PlacementContainer.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2007-2018 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Edit.Tools; -using Container = System.ComponentModel.Container; - -namespace osu.Game.Screens.Edit.Screens.Compose.Layers -{ - public class PlacementContainer : CompositeDrawable - { - private readonly Container maskContainer; - - public PlacementContainer() - { - RelativeSizeAxes = Axes.Both; - } - - private HitObjectCompositionTool currentTool; - - /// - /// The current placement tool. - /// - public HitObjectCompositionTool CurrentTool - { - get => currentTool; - set - { - if (currentTool == value) - return; - currentTool = value; - - Refresh(); - } - } - - /// - /// Refreshes the current placement tool. - /// - public void Refresh() - { - ClearInternal(); - - var mask = CurrentTool?.CreatePlacementMask(); - if (mask != null) - InternalChild = mask; - } - } -} diff --git a/osu.Game/Screens/Edit/Screens/Setup/Components/LabelledComponents/LabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs similarity index 98% rename from osu.Game/Screens/Edit/Screens/Setup/Components/LabelledComponents/LabelledTextBox.cs rename to osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs index 94200b7f4e..626c59981c 100644 --- a/osu.Game/Screens/Edit/Screens/Setup/Components/LabelledComponents/LabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/Components/LabelledComponents/LabelledTextBox.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; -using OpenTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -10,8 +9,9 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using OpenTK.Graphics; -namespace osu.Game.Screens.Edit.Screens.Setup.Components.LabelledComponents +namespace osu.Game.Screens.Edit.Setup.Components.LabelledComponents { public class LabelledTextBox : CompositeDrawable { diff --git a/osu.Game/Tests/Visual/EditorClockTestCase.cs b/osu.Game/Tests/Visual/EditorClockTestCase.cs index ebede74171..479ed385e2 100644 --- a/osu.Game/Tests/Visual/EditorClockTestCase.cs +++ b/osu.Game/Tests/Visual/EditorClockTestCase.cs @@ -7,7 +7,6 @@ using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Screens.Compose; namespace osu.Game.Tests.Visual { diff --git a/osu.Game/Tests/Visual/EditorTestCase.cs b/osu.Game/Tests/Visual/EditorTestCase.cs index 2ab121fcc9..2d02509b58 100644 --- a/osu.Game/Tests/Visual/EditorTestCase.cs +++ b/osu.Game/Tests/Visual/EditorTestCase.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Rulesets; using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Screens; using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual diff --git a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs similarity index 78% rename from osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs rename to osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs index adf74b9a7d..f893d8456b 100644 --- a/osu.Game/Tests/Visual/HitObjectPlacementMaskTestCase.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestCase.cs @@ -8,17 +8,17 @@ using osu.Framework.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Screens.Edit.Screens.Compose; +using osu.Game.Screens.Edit.Compose; namespace osu.Game.Tests.Visual { [Cached(Type = typeof(IPlacementHandler))] - public abstract class HitObjectPlacementMaskTestCase : OsuTestCase, IPlacementHandler + public abstract class PlacementBlueprintTestCase : OsuTestCase, IPlacementHandler { private readonly Container hitObjectContainer; - private PlacementMask currentMask; + private PlacementBlueprint currentBlueprint; - protected HitObjectPlacementMaskTestCase() + protected PlacementBlueprintTestCase() { Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2; @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - Add(currentMask = CreateMask()); + Add(currentBlueprint = CreateBlueprint()); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -51,8 +51,8 @@ namespace osu.Game.Tests.Visual { hitObjectContainer.Add(CreateHitObject(hitObject)); - Remove(currentMask); - Add(currentMask = CreateMask()); + Remove(currentBlueprint); + Add(currentBlueprint = CreateBlueprint()); } public void Delete(HitObject hitObject) @@ -60,6 +60,6 @@ namespace osu.Game.Tests.Visual } protected abstract DrawableHitObject CreateHitObject(HitObject hitObject); - protected abstract PlacementMask CreateMask(); + protected abstract PlacementBlueprint CreateBlueprint(); } } diff --git a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs similarity index 64% rename from osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs rename to osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs index 3ba6841280..b1df849a67 100644 --- a/osu.Game/Tests/Visual/HitObjectSelectionMaskTestCase.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestCase.cs @@ -10,14 +10,14 @@ using osu.Game.Rulesets.Edit; namespace osu.Game.Tests.Visual { - public abstract class HitObjectSelectionMaskTestCase : OsuTestCase + public abstract class SelectionBlueprintTestCase : OsuTestCase { - private SelectionMask mask; + private SelectionBlueprint blueprint; protected override Container Content => content ?? base.Content; private readonly Container content; - protected HitObjectSelectionMaskTestCase() + protected SelectionBlueprintTestCase() { base.Content.Add(content = new Container { @@ -29,19 +29,19 @@ namespace osu.Game.Tests.Visual [BackgroundDependencyLoader] private void load() { - base.Content.Add(mask = CreateMask()); - mask.SelectionRequested += (_, __) => mask.Select(); + base.Content.Add(blueprint = CreateBlueprint()); + blueprint.SelectionRequested += (_, __) => blueprint.Select(); - AddStep("Select", () => mask.Select()); - AddStep("Deselect", () => mask.Deselect()); + AddStep("Select", () => blueprint.Select()); + AddStep("Deselect", () => blueprint.Deselect()); } protected override bool OnClick(ClickEvent e) { - mask.Deselect(); + blueprint.Deselect(); return true; } - protected abstract SelectionMask CreateMask(); + protected abstract SelectionBlueprint CreateBlueprint(); } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b4cd8f9b66..9f7996a5fd 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - +