From 7713c8a45f0763a7aff7b24622e58a203c7d1c4b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 8 Apr 2021 20:19:41 +0900 Subject: [PATCH 1/5] Add support for sliderwhistle --- .../Objects/Drawables/DrawableSlider.cs | 10 +++++++--- osu.Game.Rulesets.Osu/Objects/Slider.cs | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 04708a5ece..8167a9f243 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osuTK; @@ -110,13 +111,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.LoadSamples(); - var firstSample = HitObject.Samples.FirstOrDefault(); + var firstSample = HitObject.OriginalSamples.FirstOrDefault(); if (firstSample != null) { - var clone = HitObject.SampleControlPoint.ApplyTo(firstSample).With("sliderslide"); + var samples = new List { HitObject.SampleControlPoint.ApplyTo(firstSample).With("sliderslide") }; - slidingSample.Samples = new ISampleInfo[] { clone }; + if (HitObject.OriginalSamples.Any(s => s.Name == HitSampleInfo.HIT_WHISTLE)) + samples.Add(HitObject.SampleControlPoint.ApplyTo(firstSample).With("sliderwhistle")); + + slidingSample.Samples = samples.ToArray(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index e2b6c84896..54e781bbe9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -81,6 +81,8 @@ namespace osu.Game.Rulesets.Osu.Objects public List> NodeSamples { get; set; } = new List>(); + public IList OriginalSamples { get; private set; } + private int repeatCount; public int RepeatCount @@ -147,6 +149,7 @@ namespace osu.Game.Rulesets.Osu.Objects // The samples should be attached to the slider tail, however this can only be done after LegacyLastTick is removed otherwise they would play earlier than they're intended to. // For now, the samples are attached to and played by the slider itself at the correct end time. // ToArray call is required as GetNodeSamples may fallback to Samples itself (without it it will get cleared due to the list reference being live). + OriginalSamples = Samples.ToList(); Samples = this.GetNodeSamples(repeatCount + 1).ToArray(); } From 7d291ed7d73f18bcb9bdac5f1aa26f511ee6ecf6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 8 Apr 2021 20:57:50 +0900 Subject: [PATCH 2/5] Don't serialise OriginalSamples --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 54e781bbe9..4e71d82cab 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -81,6 +81,7 @@ namespace osu.Game.Rulesets.Osu.Objects public List> NodeSamples { get; set; } = new List>(); + [JsonIgnore] public IList OriginalSamples { get; private set; } private int repeatCount; From 8efa381d3a1f71eb8e169495bf5a54f99a4a751c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 8 Apr 2021 23:13:16 +0900 Subject: [PATCH 3/5] Actually use whistle sample for sliderwhistle --- .../Objects/Drawables/DrawableSlider.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 8167a9f243..e29e28b1fa 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -111,17 +111,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.LoadSamples(); - var firstSample = HitObject.OriginalSamples.FirstOrDefault(); + var slidingSamples = new List(); - if (firstSample != null) - { - var samples = new List { HitObject.SampleControlPoint.ApplyTo(firstSample).With("sliderslide") }; + var normalSample = HitObject.OriginalSamples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL); + if (normalSample != null) + slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(normalSample).With("sliderslide")); - if (HitObject.OriginalSamples.Any(s => s.Name == HitSampleInfo.HIT_WHISTLE)) - samples.Add(HitObject.SampleControlPoint.ApplyTo(firstSample).With("sliderwhistle")); + var whistleSample = HitObject.OriginalSamples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE); + if (whistleSample != null) + slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(whistleSample).With("sliderwhistle")); - slidingSample.Samples = samples.ToArray(); - } + slidingSample.Samples = slidingSamples.ToArray(); } public override void StopAllSamples() From f2e811928bb30d2b4c5a69bfcce67f5dbac7a68e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 9 Apr 2021 15:28:08 +0900 Subject: [PATCH 4/5] Rework slider hackery to not overwrite Samples --- .../Objects/Drawables/DrawableSlider.cs | 14 +++++++++++--- osu.Game.Rulesets.Osu/Objects/Slider.cs | 12 +++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index e29e28b1fa..82b5492de6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -109,15 +109,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override void LoadSamples() { - base.LoadSamples(); + // Note: base.LoadSamples() isn't called since the slider plays the tail's hitsounds for the time being. + + if (HitObject.SampleControlPoint == null) + { + throw new InvalidOperationException($"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); + } + + Samples.Samples = HitObject.TailSamples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast().ToArray(); var slidingSamples = new List(); - var normalSample = HitObject.OriginalSamples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL); + var normalSample = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL); if (normalSample != null) slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(normalSample).With("sliderslide")); - var whistleSample = HitObject.OriginalSamples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE); + var whistleSample = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE); if (whistleSample != null) slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(whistleSample).With("sliderwhistle")); diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 4e71d82cab..8ba9597dc3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Objects public List> NodeSamples { get; set; } = new List>(); [JsonIgnore] - public IList OriginalSamples { get; private set; } + public IList TailSamples { get; private set; } private int repeatCount; @@ -146,12 +146,6 @@ namespace osu.Game.Rulesets.Osu.Objects Velocity = scoringDistance / timingPoint.BeatLength; TickDistance = scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier; - - // The samples should be attached to the slider tail, however this can only be done after LegacyLastTick is removed otherwise they would play earlier than they're intended to. - // For now, the samples are attached to and played by the slider itself at the correct end time. - // ToArray call is required as GetNodeSamples may fallback to Samples itself (without it it will get cleared due to the list reference being live). - OriginalSamples = Samples.ToList(); - Samples = this.GetNodeSamples(repeatCount + 1).ToArray(); } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) @@ -242,6 +236,10 @@ namespace osu.Game.Rulesets.Osu.Objects if (HeadCircle != null) HeadCircle.Samples = this.GetNodeSamples(0); + + // The samples should be attached to the slider tail, however this can only be done after LegacyLastTick is removed otherwise they would play earlier than they're intended to. + // For now, the samples are played by the slider itself at the correct end time. + TailSamples = this.GetNodeSamples(repeatCount + 1); } public override Judgement CreateJudgement() => OnlyJudgeNestedObjects ? new OsuIgnoreJudgement() : new OsuJudgement(); From 9b0ce2999ffe05292826c048942058da5d1679d4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 9 Apr 2021 15:28:42 +0900 Subject: [PATCH 5/5] Fix legacy encoder --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index da44b96ed3..acbf57d25f 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -273,7 +273,7 @@ namespace osu.Game.Beatmaps.Formats if (hitObject is IHasPath path) { addPathData(writer, path, position); - writer.Write(getSampleBank(hitObject.Samples, zeroBanks: true)); + writer.Write(getSampleBank(hitObject.Samples)); } else { @@ -420,15 +420,15 @@ namespace osu.Game.Beatmaps.Formats writer.Write(FormattableString.Invariant($"{endTimeData.EndTime}{suffix}")); } - private string getSampleBank(IList samples, bool banksOnly = false, bool zeroBanks = false) + private string getSampleBank(IList samples, bool banksOnly = false) { LegacySampleBank normalBank = toLegacySampleBank(samples.SingleOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)?.Bank); LegacySampleBank addBank = toLegacySampleBank(samples.FirstOrDefault(s => !string.IsNullOrEmpty(s.Name) && s.Name != HitSampleInfo.HIT_NORMAL)?.Bank); StringBuilder sb = new StringBuilder(); - sb.Append(FormattableString.Invariant($"{(zeroBanks ? 0 : (int)normalBank)}:")); - sb.Append(FormattableString.Invariant($"{(zeroBanks ? 0 : (int)addBank)}")); + sb.Append(FormattableString.Invariant($"{(int)normalBank}:")); + sb.Append(FormattableString.Invariant($"{(int)addBank}")); if (!banksOnly) {