diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 38757d4928..9952e85c70 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -37,9 +37,9 @@ namespace osu.Game.Rulesets.Catch.Objects /// public CatchHitObject HyperDashTarget; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs index bfb674d1b4..db0632a07d 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using OpenTK; @@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable RelativeChildSize = new Vector2(1, (float)HitObject.Duration) }; - foreach (CatchHitObject tick in s.Ticks) + foreach (CatchHitObject tick in s.NestedHitObjects.OfType()) { TinyDroplet tiny = tick as TinyDroplet; if (tiny != null) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index b0540b2a4d..8e496c3b0c 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -11,8 +11,6 @@ using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using OpenTK; -using osu.Framework.Lists; -using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Rulesets.Catch.Objects { @@ -30,14 +28,9 @@ namespace osu.Game.Rulesets.Catch.Objects public double Velocity; public double TickDistance; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); @@ -48,95 +41,94 @@ namespace osu.Game.Rulesets.Catch.Objects TickDistance = scoringDistance / difficulty.SliderTickRate; } - public IEnumerable Ticks + protected override void CreateNestedHitObjects() { - get + base.CreateNestedHitObjects(); + + createTicks(); + } + + private void createTicks() + { + if (TickDistance == 0) + return; + + var length = Curve.Distance; + var tickDistance = Math.Min(TickDistance, length); + var repeatDuration = length / Velocity; + + var minDistanceFromEnd = Velocity * 0.01; + + AddNested(new Fruit { - SortedList ticks = new SortedList((a, b) => a.StartTime.CompareTo(b.StartTime)); + Samples = Samples, + ComboColour = ComboColour, + StartTime = StartTime, + X = X + }); - if (TickDistance == 0) - return ticks; + for (var repeat = 0; repeat < RepeatCount; repeat++) + { + var repeatStartTime = StartTime + repeat * repeatDuration; + var reversed = repeat % 2 == 1; - var length = Curve.Distance; - var tickDistance = Math.Min(TickDistance, length); - var repeatDuration = length / Velocity; - - var minDistanceFromEnd = Velocity * 0.01; - - ticks.Add(new Fruit + for (var d = tickDistance; d <= length; d += tickDistance) { - Samples = Samples, - ComboColour = ComboColour, - StartTime = StartTime, - X = X - }); + if (d > length - minDistanceFromEnd) + break; - for (var repeat = 0; repeat < RepeatCount; repeat++) - { - var repeatStartTime = StartTime + repeat * repeatDuration; - var reversed = repeat % 2 == 1; + var timeProgress = d / length; + var distanceProgress = reversed ? 1 - timeProgress : timeProgress; - for (var d = tickDistance; d <= length; d += tickDistance) + var lastTickTime = repeatStartTime + timeProgress * repeatDuration; + AddNested(new Droplet { - if (d > length - minDistanceFromEnd) - break; - - var timeProgress = d / length; - var distanceProgress = reversed ? 1 - timeProgress : timeProgress; - - var lastTickTime = repeatStartTime + timeProgress * repeatDuration; - ticks.Add(new Droplet - { - StartTime = lastTickTime, - ComboColour = ComboColour, - X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } - - double tinyTickInterval = tickDistance / length * repeatDuration; - while (tinyTickInterval > 100) - tinyTickInterval /= 2; - - for (double t = 0; t < repeatDuration; t += tinyTickInterval) - { - double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration; - - ticks.Add(new TinyDroplet - { - StartTime = repeatStartTime + t, - ComboColour = ComboColour, - X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } - - ticks.Add(new Fruit - { - Samples = Samples, + StartTime = lastTickTime, ComboColour = ComboColour, - StartTime = repeatStartTime + repeatDuration, - X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH + X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) }); } - if (controlPointInfo != null && difficulty != null) - ticks.ForEach(t => t.ApplyDefaults(controlPointInfo, difficulty)); + double tinyTickInterval = tickDistance / length * repeatDuration; + while (tinyTickInterval > 100) + tinyTickInterval /= 2; - return ticks; + for (double t = 0; t < repeatDuration; t += tinyTickInterval) + { + double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration; + + AddNested(new TinyDroplet + { + StartTime = repeatStartTime + t, + ComboColour = ComboColour, + X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, + Samples = new SampleInfoList(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); + } + + AddNested(new Fruit + { + Samples = Samples, + ComboColour = ComboColour, + StartTime = repeatStartTime + repeatDuration, + X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH + }); } + } + public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity; public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH; diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index 0806c4b29d..3826fd1129 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects; @@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Scoring AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); - foreach (var unused in stream.Ticks) + foreach (var unused in stream.NestedHitObjects.OfType()) AddJudgement(new CatchJudgement { Result = HitResult.Perfect }); continue; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 237df72480..7b207ca229 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables } }); - foreach (var tick in HitObject.Ticks) + foreach (var tick in HitObject.NestedHitObjects.OfType()) { var drawableTick = new DrawableHoldNoteTick(tick) { diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 2a62eaa2ef..f72bed3142 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; @@ -63,15 +62,9 @@ namespace osu.Game.Rulesets.Mania.Objects /// private double tickSpacing = 50; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate; @@ -80,34 +73,27 @@ namespace osu.Game.Rulesets.Mania.Objects Tail.ApplyDefaults(controlPointInfo, difficulty); } - /// - /// The scoring scoring ticks of the hold note. - /// - public IEnumerable Ticks => ticks ?? (ticks = createTicks()); - private List ticks; - - private List createTicks() + protected override void CreateNestedHitObjects() { - var ret = new List(); + base.CreateNestedHitObjects(); + createTicks(); + } + + private void createTicks() + { if (tickSpacing == 0) - return ret; + return; for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing) { - var tick = new HoldNoteTick + AddNested(new HoldNoteTick { StartTime = t, Column = Column - }; - - if (controlPointInfo != null && difficulty != null) - tick.ApplyDefaults(controlPointInfo, difficulty); - - ret.Add(tick); + }); } - return ret; } /// @@ -121,9 +107,9 @@ namespace osu.Game.Rulesets.Mania.Objects /// private const double release_window_lenience = 1.5; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); HitWindows *= release_window_lenience; } diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index c4d5a13352..51a9a18afa 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Mania.Objects [JsonIgnore] public HitWindows HitWindows { get; protected set; } = new HitWindows(); - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); HitWindows = new HitWindows(difficulty.OverallDifficulty); } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index 9b8ebe0070..012137f555 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Mania.Scoring AddJudgement(new ManiaJudgement { Result = HitResult.Perfect }); // Ticks - int tickCount = holdNote.Ticks.Count(); + int tickCount = holdNote.NestedHitObjects.OfType().Count(); for (int i = 0; i < tickCount; i++) AddJudgement(new HoldNoteTickJudgement { Result = HitResult.Perfect }); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index a91d846aa7..57c1ffab00 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddNested(initialCircle); var repeatDuration = s.Curve.Distance / s.Velocity; - foreach (var tick in s.Ticks) + foreach (var tick in s.NestedHitObjects.OfType()) { var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration; var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AddNested(drawableTick); } - foreach (var repeatPoint in s.RepeatPoints) + foreach (var repeatPoint in s.NestedHitObjects.OfType()) { var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration; var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? TIME_FADEIN : TIME_FADEIN / 2); diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index e6bfd8a277..7532387aa2 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Osu.Objects return HitResult.Miss; } - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2; } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index af50667d42..24398c2235 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -74,15 +74,9 @@ namespace osu.Game.Rulesets.Osu.Objects public double Velocity; public double TickDistance; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); @@ -105,85 +99,78 @@ namespace osu.Game.Rulesets.Osu.Objects public int RepeatAt(double progress) => (int)(progress * RepeatCount); - public IEnumerable Ticks + protected override void CreateNestedHitObjects() { - get + base.CreateNestedHitObjects(); + + createTicks(); + createRepeatPoints(); + } + + private void createTicks() + { + if (TickDistance == 0) return; + + var length = Curve.Distance; + var tickDistance = Math.Min(TickDistance, length); + var repeatDuration = length / Velocity; + + var minDistanceFromEnd = Velocity * 0.01; + + for (var repeat = 0; repeat < RepeatCount; repeat++) { - if (TickDistance == 0) yield break; + var repeatStartTime = StartTime + repeat * repeatDuration; + var reversed = repeat % 2 == 1; - var length = Curve.Distance; - var tickDistance = Math.Min(TickDistance, length); - var repeatDuration = length / Velocity; - - var minDistanceFromEnd = Velocity * 0.01; - - for (var repeat = 0; repeat < RepeatCount; repeat++) + for (var d = tickDistance; d <= length; d += tickDistance) { - var repeatStartTime = StartTime + repeat * repeatDuration; - var reversed = repeat % 2 == 1; + if (d > length - minDistanceFromEnd) + break; - for (var d = tickDistance; d <= length; d += tickDistance) + var distanceProgress = d / length; + var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; + + AddNested(new SliderTick { - if (d > length - minDistanceFromEnd) - break; - - var distanceProgress = d / length; - var timeProgress = reversed ? 1 - distanceProgress : distanceProgress; - - var ret = new SliderTick + RepeatIndex = repeat, + StartTime = repeatStartTime + timeProgress * repeatDuration, + Position = Curve.PositionAt(distanceProgress), + StackHeight = StackHeight, + Scale = Scale, + ComboColour = ComboColour, + Samples = new SampleInfoList(Samples.Select(s => new SampleInfo { - RepeatIndex = repeat, - StartTime = repeatStartTime + timeProgress * repeatDuration, - Position = Curve.PositionAt(distanceProgress), - StackHeight = StackHeight, - Scale = Scale, - ComboColour = ComboColour, - Samples = new SampleInfoList(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }; - - if (controlPointInfo != null && difficulty != null) - ret.ApplyDefaults(controlPointInfo, difficulty); - - yield return ret; - } + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); } } } - public IEnumerable RepeatPoints + + private void createRepeatPoints() { - get + var length = Curve.Distance; + var repeatPointDistance = Math.Min(Distance, length); + var repeatDuration = length / Velocity; + + for (var repeat = 1; repeat < RepeatCount; repeat++) { - var length = Curve.Distance; - var repeatPointDistance = Math.Min(Distance, length); - var repeatDuration = length / Velocity; - - for (var repeat = 1; repeat < RepeatCount; repeat++) + for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) { - for (var d = repeatPointDistance; d <= length; d += repeatPointDistance) + var repeatStartTime = StartTime + repeat * repeatDuration; + var distanceProgress = d / length; + + AddNested(new RepeatPoint { - var repeatStartTime = StartTime + repeat * repeatDuration; - var distanceProgress = d / length; - - var ret = new RepeatPoint - { - RepeatIndex = repeat, - StartTime = repeatStartTime, - Position = Curve.PositionAt(distanceProgress), - StackHeight = StackHeight, - Scale = Scale, - ComboColour = ComboColour, - }; - - if (controlPointInfo != null && difficulty != null) - ret.ApplyDefaults(controlPointInfo, difficulty); - - yield return ret; - } + RepeatIndex = repeat, + StartTime = repeatStartTime, + Position = Curve.PositionAt(distanceProgress), + StackHeight = StackHeight, + Scale = Scale, + ComboColour = ComboColour, + }); } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index c4f5dfe97a..7d1bd9239d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Osu.Objects public override bool NewCombo => true; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5)); diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 89821a10fb..11c0df0c8c 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing } }); - var scoringTimes = slider.Ticks.Select(t => t.StartTime).Concat(slider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t); + var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime); foreach (var time in scoringTimes) computeVertex(time); computeVertex(slider.EndTime); diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs index cd6b6c5e27..2cf321da50 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Scoring countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle); beatmapMaxCombo = Beatmap.HitObjects.Count; - beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.RepeatCount + s.Ticks.Count()); + beatmapMaxCombo += Beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.Count) + 1; } public override double Calculate(Dictionary categoryRatings = null) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 6e5dd18c46..ad9737af52 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using System.Linq; using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; @@ -39,11 +40,11 @@ namespace osu.Game.Rulesets.Osu.Scoring AddJudgement(new OsuJudgement { Result = HitResult.Great }); // Ticks - foreach (var unused in slider.Ticks) + foreach (var unused in slider.NestedHitObjects.OfType()) AddJudgement(new OsuJudgement { Result = HitResult.Great }); //Repeats - foreach (var unused in slider.RepeatPoints) + foreach (var unused in slider.NestedHitObjects.OfType()) AddJudgement(new OsuJudgement { Result = HitResult.Great }); } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 2396f3bf91..75e988ced6 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeChildSize = new Vector2((float)HitObject.Duration, 1) }); - foreach (var tick in drumRoll.Ticks) + foreach (var tick in drumRoll.NestedHitObjects.OfType()) { var newTick = new DrawableDrumRollTick(tick); newTick.OnJudgement += onTickJudgement; diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index ff20a16c7b..4104b59979 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -3,7 +3,6 @@ using osu.Game.Rulesets.Objects.Types; using System; -using System.Collections.Generic; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -37,52 +36,40 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double RequiredGreatHits { get; protected set; } - /// - /// Total number of drum roll ticks. - /// - public int TotalTicks => Ticks.Count(); - - /// - /// Initializes the drum roll ticks if not initialized and returns them. - /// - public IEnumerable Ticks => ticks ?? (ticks = createTicks()); - - private List ticks; - /// /// The length (in milliseconds) between ticks of this drumroll. /// Half of this value is the hit window of the ticks. /// private double tickSpacing = 100; - private ControlPointInfo controlPointInfo; - private BeatmapDifficulty difficulty; - - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); - this.controlPointInfo = controlPointInfo; - this.difficulty = difficulty; + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / TickRate; - RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); - RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); + RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); + RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); } - private List createTicks() + protected override void CreateNestedHitObjects() { - var ret = new List(); + base.CreateNestedHitObjects(); + createTicks(); + } + + private void createTicks() + { if (tickSpacing == 0) - return ret; + return; bool first = true; for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing) { - var tick = new DrumRollTick + AddNested(new DrumRollTick { FirstTick = first, TickSpacing = tickSpacing, @@ -94,16 +81,10 @@ namespace osu.Game.Rulesets.Taiko.Objects Name = @"slidertick", Volume = s.Volume })) - }; + }); - if (controlPointInfo != null && difficulty != null) - tick.ApplyDefaults(controlPointInfo, difficulty); - - ret.Add(tick); first = false; } - - return ret; } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Hit.cs b/osu.Game.Rulesets.Taiko/Objects/Hit.cs index 03b9be4157..1b9b44fd99 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Hit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Hit.cs @@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double HitWindowMiss = 95; - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20); HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50); diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs index c3e5597f43..df1a19267f 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Taiko.Objects; @@ -83,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Replays } else if (drumRoll != null) { - foreach (var tick in drumRoll.Ticks) + foreach (var tick in drumRoll.NestedHitObjects.OfType()) { Frames.Add(new ReplayFrame(tick.StartTime, null, null, hitButton ? ReplayButtonState.Left1 : ReplayButtonState.Left2)); hitButton = !hitButton; diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 0048566b15..df9ce5e2eb 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; @@ -88,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring } else if (obj is DrumRoll) { - for (int i = 0; i < ((DrumRoll)obj).TotalTicks; i++) + for (int i = 0; i < ((DrumRoll)obj).NestedHitObjects.OfType().Count(); i++) { AddJudgement(new TaikoDrumRollTickJudgement { Result = HitResult.Great }); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 66e34eac32..9e331dfea9 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -1,7 +1,10 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using Newtonsoft.Json; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Lists; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -40,12 +43,26 @@ namespace osu.Game.Rulesets.Objects [JsonIgnore] public bool Kiai { get; private set; } + private readonly SortedList nestedHitObjects = new SortedList((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); + + [JsonIgnore] + public IReadOnlyList NestedHitObjects => nestedHitObjects; + /// /// Applies default values to this HitObject. /// /// The control points. /// The difficulty settings to use. - public virtual void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + ApplyDefaultsToSelf(controlPointInfo, difficulty); + + nestedHitObjects.Clear(); + CreateNestedHitObjects(); + nestedHitObjects.ForEach(h => h.ApplyDefaults(controlPointInfo, difficulty)); + } + + protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime); EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime); @@ -53,5 +70,11 @@ namespace osu.Game.Rulesets.Objects Kiai = effectPoint.KiaiMode; SoundControlPoint = soundPoint; } + + protected virtual void CreateNestedHitObjects() + { + } + + protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs index 479cacc52b..698b74cc28 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -46,9 +46,9 @@ namespace osu.Game.Rulesets.Objects.Legacy throw new NotImplementedException(); } - public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { - base.ApplyDefaults(controlPointInfo, difficulty); + base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);