From e2001148d570ca139df57cf7cbd606adf8f50363 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Tue, 8 Mar 2022 21:47:54 +0000 Subject: [PATCH 1/5] Implement strict tracking mod --- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 3 + .../Mods/OsuModStrictTracking.cs | 59 +++++++++++++++++++ .../Objects/SliderTailCircle.cs | 4 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index e04a30d06c..f46573c494 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using osu.Framework.Bindables; using osu.Game.Configuration; @@ -16,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModClassic : ModClassic, IApplicableToHitObject, IApplicableToDrawableHitObject, IApplicableToDrawableRuleset { + public override Type[] IncompatibleMods => new[] { typeof(OsuModStrictTracking) }; + [SettingSource("No slider head accuracy requirement", "Scores sliders proportionally to the number of ticks hit.")] public Bindable NoSliderHeadAccuracy { get; } = new BindableBool(true); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs new file mode 100644 index 0000000000..13da422049 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModStrictTracking : Mod, IApplicableToDifficulty, IApplicableToDrawableHitObject, IApplicableToHitObject + { + public override string Name => @"Strict Tracking"; + public override string Acronym => @"ST"; + public override IconUsage? Icon => FontAwesome.Solid.PenFancy; + public override ModType Type => ModType.DifficultyIncrease; + public override string Description => @"Follow circles just got serious..."; + public override double ScoreMultiplier => 1.0; + public override Type[] IncompatibleMods => new[] { typeof(ModClassic) }; + + public void ApplyToDifficulty(BeatmapDifficulty difficulty) + { + difficulty.SliderTickRate = 0.0; + } + + public void ApplyToDrawableHitObject(DrawableHitObject drawable) + { + if (drawable is DrawableSlider slider) + { + slider.Tracking.ValueChanged += e => + { + if (e.NewValue || slider.Judged) return; + + slider.MissForcefully(); + + foreach (var o in slider.NestedHitObjects) + { + if (o is DrawableOsuHitObject h && !o.Judged) + h.MissForcefully(); + } + }; + } + } + + public void ApplyToHitObject(HitObject hitObject) + { + switch (hitObject) + { + case Slider slider: + slider.TailCircle.JudgeAsSliderTick = true; + break; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index f9450062f4..70459dc432 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -14,12 +14,14 @@ namespace osu.Game.Rulesets.Osu.Objects /// public class SliderTailCircle : SliderEndCircle { + public bool JudgeAsSliderTick = false; + public SliderTailCircle(Slider slider) : base(slider) { } - public override Judgement CreateJudgement() => new SliderTailJudgement(); + public override Judgement CreateJudgement() => JudgeAsSliderTick ? (OsuJudgement)new SliderTickJudgement() : new SliderTailJudgement(); public class SliderTailJudgement : OsuJudgement { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 5ade164566..faaab1a8e2 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -159,6 +159,7 @@ namespace osu.Game.Rulesets.Osu new MultiMod(new OsuModDoubleTime(), new OsuModNightcore()), new OsuModHidden(), new MultiMod(new OsuModFlashlight(), new OsuModBlinds()), + new OsuModStrictTracking() }; case ModType.Conversion: From 149cfd338dd5e77dca9cc7f612ab311914176cfd Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sat, 19 Mar 2022 18:29:44 +0000 Subject: [PATCH 2/5] Use new mod-related object types for Strict Tracking --- .../StrictTrackingDrawableSliderTail.cs | 12 ++++ .../Mods/Objects/StrictTrackingSlider.cs | 70 +++++++++++++++++++ .../Objects/StrictTrackingSliderTailCircle.cs | 19 +++++ .../Mods/OsuModStrictTracking.cs | 40 +++++++---- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 +- osu.Game/Rulesets/UI/Playfield.cs | 2 +- 6 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs create mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs new file mode 100644 index 0000000000..110b09f4f9 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs @@ -0,0 +1,12 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Mods.Objects +{ + public class StrictTrackingDrawableSliderTail : DrawableSliderTail + { + public override bool DisplayResult => true; + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs new file mode 100644 index 0000000000..bf0a57d871 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs @@ -0,0 +1,70 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Mods.Objects +{ + public class StrictTrackingSlider : Slider + { + public StrictTrackingSlider(Slider original) + { + StartTime = original.StartTime; + Samples = original.Samples; + Path = original.Path; + NodeSamples = original.NodeSamples; + RepeatCount = original.RepeatCount; + Position = original.Position; + NewCombo = original.NewCombo; + ComboOffset = original.ComboOffset; + LegacyLastTickOffset = original.LegacyLastTickOffset; + TickDistanceMultiplier = original.TickDistanceMultiplier; + } + + protected override void CreateNestedHitObjects(CancellationToken cancellationToken) + { + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); + + foreach (var e in sliderEvents) + { + switch (e.Type) + { + case SliderEventType.Head: + AddNested(HeadCircle = new SliderHeadCircle + { + StartTime = e.Time, + Position = Position, + StackHeight = StackHeight, + }); + break; + + case SliderEventType.LegacyLastTick: + AddNested(TailCircle = new StrictTrackingSliderTailCircle(this) + { + RepeatIndex = e.SpanIndex, + StartTime = e.Time, + Position = EndPosition, + StackHeight = StackHeight + }); + break; + + case SliderEventType.Repeat: + AddNested(new SliderRepeat(this) + { + RepeatIndex = e.SpanIndex, + StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration, + Position = Position + Path.PositionAt(e.PathProgress), + StackHeight = StackHeight, + Scale = Scale, + }); + break; + } + } + + UpdateNestedSamples(); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs new file mode 100644 index 0000000000..7d93f2cf39 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Mods.Objects +{ + public class StrictTrackingSliderTailCircle : SliderTailCircle + { + public StrictTrackingSliderTailCircle(Slider slider) + : base(slider) + { + } + + public override Judgement CreateJudgement() => new OsuJudgement(); + } +} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 13da422049..255ac4fa22 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -2,17 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Mods.Objects; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModStrictTracking : Mod, IApplicableToDifficulty, IApplicableToDrawableHitObject, IApplicableToHitObject + public class OsuModStrictTracking : Mod, IApplicableAfterBeatmapConversion, IApplicableToDrawableHitObject, IApplicableToDrawableRuleset { public override string Name => @"Strict Tracking"; public override string Acronym => @"ST"; @@ -22,11 +25,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModClassic) }; - public void ApplyToDifficulty(BeatmapDifficulty difficulty) - { - difficulty.SliderTickRate = 0.0; - } - public void ApplyToDrawableHitObject(DrawableHitObject drawable) { if (drawable is DrawableSlider slider) @@ -46,14 +44,30 @@ namespace osu.Game.Rulesets.Osu.Mods } } - public void ApplyToHitObject(HitObject hitObject) + public void ApplyToBeatmap(IBeatmap beatmap) { - switch (hitObject) + var osuBeatmap = (OsuBeatmap)beatmap; + + if (osuBeatmap.HitObjects.Count == 0) return; + + var hitObjects = osuBeatmap.HitObjects.Select(ho => { - case Slider slider: - slider.TailCircle.JudgeAsSliderTick = true; - break; - } + if (ho is Slider slider) + { + var newSlider = new StrictTrackingSlider(slider); + return newSlider; + } + + return ho; + }).ToList(); + + osuBeatmap.HitObjects = hitObjects; + } + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + drawableRuleset.Playfield.RegisterPool(10, 100); + drawableRuleset.Playfield.RegisterPool(10, 100); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 5c1c3fd253..64dbab6fb8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -137,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Objects public Slider() { - SamplesBindable.CollectionChanged += (_, __) => updateNestedSamples(); + SamplesBindable.CollectionChanged += (_, __) => UpdateNestedSamples(); Path.Version.ValueChanged += _ => updateNestedPositions(); } @@ -210,7 +210,7 @@ namespace osu.Game.Rulesets.Osu.Objects } } - updateNestedSamples(); + UpdateNestedSamples(); } private void updateNestedPositions() @@ -224,7 +224,7 @@ namespace osu.Game.Rulesets.Osu.Objects TailCircle.Position = EndPosition; } - private void updateNestedSamples() + protected void UpdateNestedSamples() { var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 30e71dde1c..940b8d1ac1 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -308,7 +308,7 @@ namespace osu.Game.Rulesets.UI /// /// The type. /// The receiver for s. - protected void RegisterPool(int initialSize, int? maximumSize = null) + public void RegisterPool(int initialSize, int? maximumSize = null) where TObject : HitObject where TDrawable : DrawableHitObject, new() => RegisterPool(new DrawablePool(initialSize, maximumSize)); From 52d6f083dc2ab487c9fdd11905644296a3f41830 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sat, 19 Mar 2022 23:42:12 +0000 Subject: [PATCH 3/5] Only miss slider tail on untrack --- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 255ac4fa22..b8d7134e5f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -33,13 +33,10 @@ namespace osu.Game.Rulesets.Osu.Mods { if (e.NewValue || slider.Judged) return; - slider.MissForcefully(); + var tail = slider.NestedHitObjects.OfType().First(); - foreach (var o in slider.NestedHitObjects) - { - if (o is DrawableOsuHitObject h && !o.Judged) - h.MissForcefully(); - } + if (!tail.Judged) + tail.MissForcefully(); }; } } @@ -66,7 +63,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Playfield.RegisterPool(10, 100); drawableRuleset.Playfield.RegisterPool(10, 100); } } From 35e2e6a4e75eb2ab8e1ba9bc30d357971977f88d Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sun, 20 Mar 2022 15:41:46 +0000 Subject: [PATCH 4/5] Remove slider tick judgement flag --- osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 70459dc432..f9450062f4 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -14,14 +14,12 @@ namespace osu.Game.Rulesets.Osu.Objects /// public class SliderTailCircle : SliderEndCircle { - public bool JudgeAsSliderTick = false; - public SliderTailCircle(Slider slider) : base(slider) { } - public override Judgement CreateJudgement() => JudgeAsSliderTick ? (OsuJudgement)new SliderTickJudgement() : new SliderTailJudgement(); + public override Judgement CreateJudgement() => new SliderTailJudgement(); public class SliderTailJudgement : OsuJudgement { From d3742a91a80262ef7038665e6de01a3bb81f5060 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Sun, 20 Mar 2022 15:56:41 +0000 Subject: [PATCH 5/5] Nest specific object classes within the mod --- .../StrictTrackingDrawableSliderTail.cs | 12 --- .../Mods/Objects/StrictTrackingSlider.cs | 70 ---------------- .../Objects/StrictTrackingSliderTailCircle.cs | 19 ----- .../Mods/OsuModStrictTracking.cs | 81 ++++++++++++++++++- 4 files changed, 80 insertions(+), 102 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs delete mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs delete mode 100644 osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs deleted file mode 100644 index 110b09f4f9..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingDrawableSliderTail.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Osu.Objects.Drawables; - -namespace osu.Game.Rulesets.Osu.Mods.Objects -{ - public class StrictTrackingDrawableSliderTail : DrawableSliderTail - { - public override bool DisplayResult => true; - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs deleted file mode 100644 index bf0a57d871..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSlider.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Threading; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Mods.Objects -{ - public class StrictTrackingSlider : Slider - { - public StrictTrackingSlider(Slider original) - { - StartTime = original.StartTime; - Samples = original.Samples; - Path = original.Path; - NodeSamples = original.NodeSamples; - RepeatCount = original.RepeatCount; - Position = original.Position; - NewCombo = original.NewCombo; - ComboOffset = original.ComboOffset; - LegacyLastTickOffset = original.LegacyLastTickOffset; - TickDistanceMultiplier = original.TickDistanceMultiplier; - } - - protected override void CreateNestedHitObjects(CancellationToken cancellationToken) - { - var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); - - foreach (var e in sliderEvents) - { - switch (e.Type) - { - case SliderEventType.Head: - AddNested(HeadCircle = new SliderHeadCircle - { - StartTime = e.Time, - Position = Position, - StackHeight = StackHeight, - }); - break; - - case SliderEventType.LegacyLastTick: - AddNested(TailCircle = new StrictTrackingSliderTailCircle(this) - { - RepeatIndex = e.SpanIndex, - StartTime = e.Time, - Position = EndPosition, - StackHeight = StackHeight - }); - break; - - case SliderEventType.Repeat: - AddNested(new SliderRepeat(this) - { - RepeatIndex = e.SpanIndex, - StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration, - Position = Position + Path.PositionAt(e.PathProgress), - StackHeight = StackHeight, - Scale = Scale, - }); - break; - } - } - - UpdateNestedSamples(); - } - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs b/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs deleted file mode 100644 index 7d93f2cf39..0000000000 --- a/osu.Game.Rulesets.Osu/Mods/Objects/StrictTrackingSliderTailCircle.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Osu.Objects; - -namespace osu.Game.Rulesets.Osu.Mods.Objects -{ - public class StrictTrackingSliderTailCircle : SliderTailCircle - { - public StrictTrackingSliderTailCircle(Slider slider) - : base(slider) - { - } - - public override Judgement CreateJudgement() => new OsuJudgement(); - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index b8d7134e5f..ee325db66a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -3,12 +3,16 @@ using System; using System.Linq; +using System.Threading; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Beatmaps; -using osu.Game.Rulesets.Osu.Mods.Objects; +using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.UI; @@ -65,5 +69,80 @@ namespace osu.Game.Rulesets.Osu.Mods { drawableRuleset.Playfield.RegisterPool(10, 100); } + + private class StrictTrackingSliderTailCircle : SliderTailCircle + { + public StrictTrackingSliderTailCircle(Slider slider) + : base(slider) + { + } + + public override Judgement CreateJudgement() => new OsuJudgement(); + } + + private class StrictTrackingDrawableSliderTail : DrawableSliderTail + { + public override bool DisplayResult => true; + } + + private class StrictTrackingSlider : Slider + { + public StrictTrackingSlider(Slider original) + { + StartTime = original.StartTime; + Samples = original.Samples; + Path = original.Path; + NodeSamples = original.NodeSamples; + RepeatCount = original.RepeatCount; + Position = original.Position; + NewCombo = original.NewCombo; + ComboOffset = original.ComboOffset; + LegacyLastTickOffset = original.LegacyLastTickOffset; + TickDistanceMultiplier = original.TickDistanceMultiplier; + } + + protected override void CreateNestedHitObjects(CancellationToken cancellationToken) + { + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); + + foreach (var e in sliderEvents) + { + switch (e.Type) + { + case SliderEventType.Head: + AddNested(HeadCircle = new SliderHeadCircle + { + StartTime = e.Time, + Position = Position, + StackHeight = StackHeight, + }); + break; + + case SliderEventType.LegacyLastTick: + AddNested(TailCircle = new StrictTrackingSliderTailCircle(this) + { + RepeatIndex = e.SpanIndex, + StartTime = e.Time, + Position = EndPosition, + StackHeight = StackHeight + }); + break; + + case SliderEventType.Repeat: + AddNested(new SliderRepeat(this) + { + RepeatIndex = e.SpanIndex, + StartTime = StartTime + (e.SpanIndex + 1) * SpanDuration, + Position = Position + Path.PositionAt(e.PathProgress), + StackHeight = StackHeight, + Scale = Scale, + }); + break; + } + } + + UpdateNestedSamples(); + } + } } }