diff --git a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs index 15b38b3e83..dceb7a9cff 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseHitObjects.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Framework.Timing; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; @@ -62,15 +61,12 @@ namespace osu.Desktop.VisualTests.Tests add(new DrawableSlider(new Slider { StartTime = framedClock.CurrentTime + 600, - CurveObject = new CurvedHitObject + ControlPoints = new List { - ControlPoints = new List - { - new Vector2(-200, 0), - new Vector2(400, 0), - }, - Distance = 400 + new Vector2(-200, 0), + new Vector2(400, 0), }, + Distance = 400, Position = new Vector2(-200, 0), Velocity = 1, TickDistance = 100, diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 0eece7fc4c..7f6f524a7a 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -19,10 +19,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { - IHasCurve curveData = original as IHasCurve; - IHasEndTime endTimeData = original as IHasEndTime; - IHasPosition positionData = original as IHasPosition; - IHasCombo comboData = original as IHasCombo; + var curveData = original as IHasCurve; + var endTimeData = original as IHasEndTime; + var positionData = original as IHasPosition; + var comboData = original as IHasCombo; if (curveData != null) { @@ -30,7 +30,11 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { StartTime = original.StartTime, Samples = original.Samples, - CurveObject = curveData, + ControlPoints = curveData.ControlPoints, + CurveType = curveData.CurveType, + Distance = curveData.Distance, + RepeatSamples = curveData.RepeatSamples, + RepeatCount = curveData.RepeatCount, Position = positionData?.Position ?? Vector2.Zero, NewCombo = comboData?.NewCombo ?? false }; diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 167bf21670..4d9d3f97ed 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -20,24 +20,33 @@ namespace osu.Game.Rulesets.Osu.Objects /// private const float base_scoring_distance = 100; - public IHasCurve CurveObject { get; set; } - - public SliderCurve Curve => CurveObject.Curve; + public readonly SliderCurve Curve = new SliderCurve(); public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity; public double Duration => EndTime - StartTime; public override Vector2 EndPosition => PositionAt(1); - public Vector2 PositionAt(double progress) => CurveObject.PositionAt(progress); - public double ProgressAt(double progress) => CurveObject.ProgressAt(progress); - public int RepeatAt(double progress) => CurveObject.RepeatAt(progress); + public List ControlPoints + { + get { return Curve.ControlPoints; } + set { Curve.ControlPoints = value; } + } - public List ControlPoints => CurveObject.ControlPoints; - public CurveType CurveType => CurveObject.CurveType; - public double Distance => CurveObject.Distance; + public CurveType CurveType + { + get { return Curve.CurveType; } + set { Curve.CurveType = value; } + } - public int RepeatCount => CurveObject.RepeatCount; + public double Distance + { + get { return Curve.Distance; } + set { Curve.Distance = value; } + } + + public List> RepeatSamples { get; set; } = new List>(); + public int RepeatCount { get; set; } = 1; private int stackHeight; public override int StackHeight @@ -63,6 +72,18 @@ namespace osu.Game.Rulesets.Osu.Objects TickDistance = scoringDistance / difficulty.SliderTickRate; } + public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress)); + + public double ProgressAt(double progress) + { + double p = progress * RepeatCount % 1; + if (RepeatAt(progress) % 2 == 1) + p = 1 - p; + return p; + } + + public int RepeatAt(double progress) => (int)(progress * RepeatCount); + public IEnumerable Ticks { get diff --git a/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs index 14b890a055..5669993e67 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficultyCalculator.cs @@ -3,7 +3,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Beatmaps; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using System; @@ -28,7 +27,7 @@ namespace osu.Game.Rulesets.Osu protected override void PreprocessHitObjects() { foreach (var h in Objects) - (h as IHasCurve)?.Curve?.Calculate(); + (h as Slider)?.Curve?.Calculate(); } protected override double CalculateInternal(Dictionary categoryDifficulty) @@ -190,4 +189,4 @@ namespace osu.Game.Rulesets.Osu Aim, }; } -} \ No newline at end of file +} diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 74a5be698e..95213417ed 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps.Formats // TODO: Not sure how far back to go, or differences between versions } - private HitObjectParser parser; + private ConvertHitObjectParser parser; private LegacySampleBank defaultSampleBank; private int defaultSampleVolume = 100; @@ -90,16 +90,16 @@ namespace osu.Game.Beatmaps.Formats switch (beatmap.BeatmapInfo.RulesetID) { case 0: - parser = new Rulesets.Objects.Legacy.Osu.HitObjectParser(); + parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); break; case 1: - parser = new Rulesets.Objects.Legacy.Taiko.HitObjectParser(); + parser = new Rulesets.Objects.Legacy.Taiko.ConvertHitObjectParser(); break; case 2: - parser = new Rulesets.Objects.Legacy.Catch.HitObjectParser(); + parser = new Rulesets.Objects.Legacy.Catch.ConvertHitObjectParser(); break; case 3: - parser = new Rulesets.Objects.Legacy.Mania.HitObjectParser(); + parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser(); break; } break; diff --git a/osu.Game/Rulesets/Objects/CurvedHitObject.cs b/osu.Game/Rulesets/Objects/CurvedHitObject.cs deleted file mode 100644 index 517c276242..0000000000 --- a/osu.Game/Rulesets/Objects/CurvedHitObject.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK; -using osu.Game.Rulesets.Objects.Types; -using System.Collections.Generic; - -namespace osu.Game.Rulesets.Objects -{ - public class CurvedHitObject : HitObject, IHasCurve - { - public SliderCurve Curve { get; } = new SliderCurve(); - - public int RepeatCount { get; set; } = 1; - - public double EndTime => 0; - public double Duration => 0; - - public List ControlPoints - { - get { return Curve.ControlPoints; } - set { Curve.ControlPoints = value; } - } - - public CurveType CurveType - { - get { return Curve.CurveType; } - set { Curve.CurveType = value; } - } - - public double Distance - { - get { return Curve.Distance; } - set { Curve.Distance = value; } - } - - public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress)); - - public double ProgressAt(double progress) - { - var p = progress * RepeatCount % 1; - if (RepeatAt(progress) % 2 == 1) - p = 1 - p; - return p; - } - - public int RepeatAt(double progress) => (int)(progress * RepeatCount); - } -} diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 240d110976..12e4ca6df1 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -4,6 +4,7 @@ using osu.Game.Audio; using osu.Game.Beatmaps.Timing; using osu.Game.Database; +using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; namespace osu.Game.Rulesets.Objects @@ -19,10 +20,14 @@ namespace osu.Game.Rulesets.Objects /// /// The time at which the HitObject starts. /// - public double StartTime { get; set; } + public double StartTime; /// /// The samples to be played when this hit object is hit. + /// + /// In the case of types, this is the sample of the curve body + /// and can be treated as the default samples for the hit object. + /// /// public List Samples = new List(); @@ -36,17 +41,24 @@ namespace osu.Game.Rulesets.Objects ControlPoint overridePoint; ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint); - foreach (var sample in Samples) - { - if (sample.Volume == 0) - sample.Volume = (overridePoint ?? timingPoint)?.SampleVolume ?? 0; + ControlPoint samplePoint = overridePoint ?? timingPoint; - // If the bank is not assigned a name, assign it from the control point - if (!string.IsNullOrEmpty(sample.Bank)) - continue; + // Initialize first sample + Samples.ForEach(s => initializeSampleInfo(s, samplePoint)); - sample.Bank = (overridePoint ?? timingPoint)?.SampleBank ?? @"normal"; - } + // Initialize any repeat samples + var repeatData = this as IHasRepeats; + repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, samplePoint))); + } + + private void initializeSampleInfo(SampleInfo sample, ControlPoint controlPoint) + { + if (sample.Volume == 0) + sample.Volume = controlPoint?.SampleVolume ?? 0; + + // If the bank is not assigned a name, assign it from the control point + if (string.IsNullOrEmpty(sample.Bank)) + sample.Bank = controlPoint?.SampleBank ?? @"normal"; } } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/Hit.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs similarity index 82% rename from osu.Game/Rulesets/Objects/Legacy/Catch/Hit.cs rename to osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs index 41dacd1265..30c10c302a 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/Hit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// Legacy osu!catch Hit-type, used for parsing Beatmaps. /// - internal sealed class Hit : HitObject, IHasCombo, IHasXPosition + internal sealed class ConvertHit : HitObject, IHasCombo, IHasXPosition { public float X { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/HitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs similarity index 75% rename from osu.Game/Rulesets/Objects/Legacy/Catch/HitObjectParser.cs rename to osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index a27244e5bd..1550772f8e 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/HitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; @@ -10,33 +11,34 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// A HitObjectParser to parse legacy osu!catch Beatmaps. /// - internal class HitObjectParser : Legacy.HitObjectParser + internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { - return new Hit + return new ConvertHit { X = position.X, NewCombo = newCombo, }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { - return new Slider + return new ConvertSlider { X = position.X, NewCombo = newCombo, ControlPoints = controlPoints, Distance = length, CurveType = curveType, + RepeatSamples = repeatSamples, RepeatCount = repeatCount }; } protected override HitObject CreateSpinner(Vector2 position, double endTime) { - return new Spinner + return new ConvertSpinner { EndTime = endTime }; diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/Slider.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSlider.cs similarity index 80% rename from osu.Game/Rulesets/Objects/Legacy/Catch/Slider.cs rename to osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSlider.cs index 865e56c847..781fe8f7fa 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/Slider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSlider.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// Legacy osu!catch Slider-type, used for parsing Beatmaps. /// - internal sealed class Slider : CurvedHitObject, IHasXPosition, IHasCombo + internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition, IHasCombo { public float X { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/Spinner.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs similarity index 84% rename from osu.Game/Rulesets/Objects/Legacy/Catch/Spinner.cs rename to osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs index 7690f42e76..0652737b12 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/Spinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch /// /// Legacy osu!catch Spinner-type, used for parsing Beatmaps. /// - internal sealed class Spinner : HitObject, IHasEndTime + internal sealed class ConvertSpinner : HitObject, IHasEndTime { public double EndTime { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/HitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs similarity index 55% rename from osu.Game/Rulesets/Objects/Legacy/HitObjectParser.cs rename to osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index c915e67ead..ad028e0cee 100644 --- a/osu.Game/Rulesets/Objects/Legacy/HitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -14,29 +14,28 @@ namespace osu.Game.Rulesets.Objects.Legacy /// /// A HitObjectParser to parse legacy Beatmaps. /// - internal abstract class HitObjectParser : Objects.HitObjectParser + internal abstract class ConvertHitObjectParser : HitObjectParser { public override HitObject Parse(string text) { string[] split = text.Split(','); - var type = (HitObjectType)int.Parse(split[3]) & ~HitObjectType.ColourHax; - bool combo = type.HasFlag(HitObjectType.NewCombo); - type &= ~HitObjectType.NewCombo; + ConvertHitObjectType type = (ConvertHitObjectType)int.Parse(split[3]) & ~ConvertHitObjectType.ColourHax; + bool combo = type.HasFlag(ConvertHitObjectType.NewCombo); + type &= ~ConvertHitObjectType.NewCombo; - int sampleVolume = 0; - string normalSampleBank = null; - string addSampleBank = null; + var soundType = (LegacySoundType)int.Parse(split[4]); + var bankInfo = new SampleBankInfo(); HitObject result; - if ((type & HitObjectType.Circle) > 0) + if ((type & ConvertHitObjectType.Circle) > 0) { result = CreateHit(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo); if (split.Length > 5) - readCustomSampleBanks(split[5], ref normalSampleBank, ref addSampleBank, ref sampleVolume); + readCustomSampleBanks(split[5], bankInfo); } - else if ((type & HitObjectType.Slider) > 0) + else if ((type & ConvertHitObjectType.Slider) > 0) { CurveType curveType = CurveType.Catmull; double length = 0; @@ -77,26 +76,74 @@ namespace osu.Game.Rulesets.Objects.Legacy if (split.Length > 7) length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture); - result = CreateSlider(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, points, length, curveType, repeatCount); - if (split.Length > 10) - readCustomSampleBanks(split[10], ref normalSampleBank, ref addSampleBank, ref sampleVolume); + readCustomSampleBanks(split[10], bankInfo); + + // One node for each repeat + the start and end nodes + // Note that the first length of the slider is considered a repeat, but there are no actual repeats happening + int nodes = Math.Max(0, repeatCount - 1) + 2; + + // Populate node sample bank infos with the default hit object sample bank + var nodeBankInfos = new List(); + for (int i = 0; i < nodes; i++) + nodeBankInfos.Add(bankInfo.Clone()); + + // Read any per-node sample banks + if (split.Length > 9 && split[9].Length > 0) + { + string[] sets = split[9].Split('|'); + for (int i = 0; i < nodes; i++) + { + if (i >= sets.Length) + break; + + SampleBankInfo info = nodeBankInfos[i]; + readCustomSampleBanks(sets[i], info); + } + } + + // Populate node sound types with the default hit object sound type + var nodeSoundTypes = new List(); + for (int i = 0; i < nodes; i++) + nodeSoundTypes.Add(soundType); + + // Read any per-node sound types + if (split.Length > 8 && split[8].Length > 0) + { + string[] adds = split[8].Split('|'); + for (int i = 0; i < nodes; i++) + { + if (i >= adds.Length) + break; + + int sound; + int.TryParse(adds[i], out sound); + nodeSoundTypes[i] = (LegacySoundType)sound; + } + } + + // Generate the final per-node samples + var nodeSamples = new List>(nodes); + for (int i = 0; i <= repeatCount; i++) + nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i])); + + result = CreateSlider(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, points, length, curveType, repeatCount, nodeSamples); } - else if ((type & HitObjectType.Spinner) > 0) + else if ((type & ConvertHitObjectType.Spinner) > 0) { result = CreateSpinner(new Vector2(512, 384) / 2, Convert.ToDouble(split[5], CultureInfo.InvariantCulture)); if (split.Length > 6) - readCustomSampleBanks(split[6], ref normalSampleBank, ref addSampleBank, ref sampleVolume); + readCustomSampleBanks(split[6], bankInfo); } - else if ((type & HitObjectType.Hold) > 0) + else if ((type & ConvertHitObjectType.Hold) > 0) { // Note: Hold is generated by BMS converts // Todo: Apparently end time is determined by samples?? // Shouldn't need implementation until mania - result = new Hold + result = new ConvertHold { Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])), NewCombo = combo @@ -106,50 +153,12 @@ namespace osu.Game.Rulesets.Objects.Legacy throw new InvalidOperationException($@"Unknown hit object type {type}"); result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); - - var soundType = (LegacySoundType)int.Parse(split[4]); - - result.Samples.Add(new SampleInfo - { - Bank = normalSampleBank, - Name = SampleInfo.HIT_NORMAL, - Volume = sampleVolume - }); - - if ((soundType & LegacySoundType.Finish) > 0) - { - result.Samples.Add(new SampleInfo - { - Bank = addSampleBank, - Name = SampleInfo.HIT_FINISH, - Volume = sampleVolume - }); - } - - if ((soundType & LegacySoundType.Whistle) > 0) - { - result.Samples.Add(new SampleInfo - { - Bank = addSampleBank, - Name = SampleInfo.HIT_WHISTLE, - Volume = sampleVolume - }); - } - - if ((soundType & LegacySoundType.Clap) > 0) - { - result.Samples.Add(new SampleInfo - { - Bank = addSampleBank, - Name = SampleInfo.HIT_CLAP, - Volume = sampleVolume - }); - } + result.Samples = convertSoundType(soundType, bankInfo); return result; } - private void readCustomSampleBanks(string str, ref string normalSampleBank, ref string addSampleBank, ref int sampleVolume) + private void readCustomSampleBanks(string str, SampleBankInfo bankInfo) { if (string.IsNullOrEmpty(str)) return; @@ -169,9 +178,11 @@ namespace osu.Game.Rulesets.Objects.Legacy if (stringAddBank == @"none") stringAddBank = null; - normalSampleBank = stringBank; - addSampleBank = stringAddBank; - sampleVolume = split.Length > 3 ? int.Parse(split[3]) : 0; + bankInfo.Normal = stringBank; + bankInfo.Add = stringAddBank; + + if (split.Length > 3) + bankInfo.Volume = int.Parse(split[3]); } /// @@ -191,8 +202,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 hit object. - protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount); + protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples); /// /// Creates a legacy Spinner-type hit object. @@ -202,6 +214,63 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The hit object. protected abstract HitObject CreateSpinner(Vector2 position, double endTime); + private List convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) + { + var soundTypes = new List + { + new SampleInfo + { + Bank = bankInfo.Normal, + Name = SampleInfo.HIT_NORMAL, + Volume = bankInfo.Volume + } + }; + + if ((type & LegacySoundType.Finish) > 0) + { + soundTypes.Add(new SampleInfo + { + Bank = bankInfo.Add, + Name = SampleInfo.HIT_FINISH, + Volume = bankInfo.Volume + }); + } + + if ((type & LegacySoundType.Whistle) > 0) + { + soundTypes.Add(new SampleInfo + { + Bank = bankInfo.Add, + Name = SampleInfo.HIT_WHISTLE, + Volume = bankInfo.Volume + }); + } + + if ((type & LegacySoundType.Clap) > 0) + { + soundTypes.Add(new SampleInfo + { + Bank = bankInfo.Add, + Name = SampleInfo.HIT_CLAP, + Volume = bankInfo.Volume + }); + } + + return soundTypes; + } + + private class SampleBankInfo + { + public string Normal; + public string Add; + public int Volume; + + public SampleBankInfo Clone() + { + return (SampleBankInfo)MemberwiseClone(); + } + } + [Flags] private enum LegacySoundType { diff --git a/osu.Game/Rulesets/Objects/Legacy/HitObjectType.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs similarity index 87% rename from osu.Game/Rulesets/Objects/Legacy/HitObjectType.cs rename to osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs index 9111e6bd12..09f005e666 100644 --- a/osu.Game/Rulesets/Objects/Legacy/HitObjectType.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectType.cs @@ -6,7 +6,7 @@ using System; namespace osu.Game.Rulesets.Objects.Legacy { [Flags] - public enum HitObjectType + internal enum ConvertHitObjectType { Circle = 1 << 0, Slider = 1 << 1, diff --git a/osu.Game/Rulesets/Objects/Legacy/Hold.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs similarity index 83% rename from osu.Game/Rulesets/Objects/Legacy/Hold.cs rename to osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs index a0a741e8e7..d79f6e324e 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Hold.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy /// /// Legacy Hold-type, used for parsing "specials" in beatmaps. /// - internal sealed class Hold : HitObject, IHasPosition, IHasCombo, IHasHold + internal sealed class ConvertHold : HitObject, IHasPosition, IHasCombo, IHasHold { public Vector2 Position { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs new file mode 100644 index 0000000000..06391a9906 --- /dev/null +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs @@ -0,0 +1,39 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Objects.Types; +using System; +using System.Collections.Generic; +using OpenTK; +using osu.Game.Audio; + +namespace osu.Game.Rulesets.Objects.Legacy +{ + internal abstract class ConvertSlider : HitObject, IHasCurve + { + public List ControlPoints { get; set; } + public CurveType CurveType { get; set; } + public double Distance { get; set; } + + public List> RepeatSamples { get; set; } + public int RepeatCount { get; set; } = 1; + + public double EndTime { get; set; } + public double Duration { get; set; } + + public Vector2 PositionAt(double progress) + { + throw new NotImplementedException(); + } + + public double ProgressAt(double progress) + { + throw new NotImplementedException(); + } + + public int RepeatAt(double progress) + { + throw new NotImplementedException(); + } + } +} diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/Hit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs similarity index 82% rename from osu.Game/Rulesets/Objects/Legacy/Mania/Hit.cs rename to osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs index 8e407fcf92..2a65b853b7 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/Hit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania /// /// Legacy osu!mania Hit-type, used for parsing Beatmaps. /// - internal sealed class Hit : HitObject, IHasXPosition, IHasCombo + internal sealed class ConvertHit : HitObject, IHasXPosition, IHasCombo { public float X { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/HitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs similarity index 76% rename from osu.Game/Rulesets/Objects/Legacy/Mania/HitObjectParser.cs rename to osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 98f0459e0a..b21857797f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/HitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; @@ -10,33 +11,34 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania /// /// A HitObjectParser to parse legacy osu!mania Beatmaps. /// - internal class HitObjectParser : Legacy.HitObjectParser + internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { - return new Hit + return new ConvertHit { X = position.X, NewCombo = newCombo, }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { - return new Slider + return new ConvertSlider { X = position.X, NewCombo = newCombo, ControlPoints = controlPoints, Distance = length, CurveType = curveType, + RepeatSamples = repeatSamples, RepeatCount = repeatCount }; } protected override HitObject CreateSpinner(Vector2 position, double endTime) { - return new Spinner + return new ConvertSpinner { X = position.X, EndTime = endTime diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/Slider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs similarity index 80% rename from osu.Game/Rulesets/Objects/Legacy/Mania/Slider.cs rename to osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs index c884ed324b..adc0c064bc 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/Slider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania /// /// Legacy osu!mania Slider-type, used for parsing Beatmaps. /// - internal sealed class Slider : CurvedHitObject, IHasXPosition, IHasCombo + internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition, IHasCombo { public float X { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/Spinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs similarity index 83% rename from osu.Game/Rulesets/Objects/Legacy/Mania/Spinner.cs rename to osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs index 3937eb003e..f72c5b9894 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/Spinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania /// /// Legacy osu!mania Spinner-type, used for parsing Beatmaps. /// - internal sealed class Spinner : HitObject, IHasEndTime, IHasXPosition + internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition { public double EndTime { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/Hit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs similarity index 84% rename from osu.Game/Rulesets/Objects/Legacy/Osu/Hit.cs rename to osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs index a30ba9b265..0c1000965c 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/Hit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// Legacy osu! Hit-type, used for parsing Beatmaps. /// - internal sealed class Hit : HitObject, IHasPosition, IHasCombo + internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo { public Vector2 Position { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/HitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs similarity index 76% rename from osu.Game/Rulesets/Objects/Legacy/Osu/HitObjectParser.cs rename to osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 227a4412c4..e45a161f52 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/HitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; @@ -10,33 +11,34 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// A HitObjectParser to parse legacy osu! Beatmaps. /// - internal class HitObjectParser : Legacy.HitObjectParser + internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { - return new Hit + return new ConvertHit { Position = position, NewCombo = newCombo, }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { - return new Slider + return new ConvertSlider { Position = position, NewCombo = newCombo, ControlPoints = controlPoints, Distance = length, CurveType = curveType, + RepeatSamples = repeatSamples, RepeatCount = repeatCount }; } protected override HitObject CreateSpinner(Vector2 position, double endTime) { - return new Spinner + return new ConvertSpinner { Position = position, EndTime = endTime diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/Slider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs similarity index 82% rename from osu.Game/Rulesets/Objects/Legacy/Osu/Slider.cs rename to osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs index 7d90c6d41e..75a6d80560 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/Slider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// Legacy osu! Slider-type, used for parsing Beatmaps. /// - internal sealed class Slider : CurvedHitObject, IHasPosition, IHasCombo + internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCombo { public Vector2 Position { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/Spinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs similarity index 85% rename from osu.Game/Rulesets/Objects/Legacy/Osu/Spinner.cs rename to osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs index ad3f9637a7..2b2dbe0765 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/Spinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu /// /// Legacy osu! Spinner-type, used for parsing Beatmaps. /// - internal sealed class Spinner : HitObject, IHasEndTime, IHasPosition + internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition { public double EndTime { get; set; } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/Hit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs similarity index 84% rename from osu.Game/Rulesets/Objects/Legacy/Taiko/Hit.cs rename to osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs index 0a9a8ac64c..7088cc480b 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/Hit.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// /// Legacy osu!taiko Hit-type, used for parsing Beatmaps. /// - internal sealed class Hit : HitObject, IHasCombo + internal sealed class ConvertHit : HitObject, IHasCombo { public bool NewCombo { get; set; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/HitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs similarity index 75% rename from osu.Game/Rulesets/Objects/Legacy/Taiko/HitObjectParser.cs rename to osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 669ee34910..2de2f217d1 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/HitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK; +using osu.Game.Audio; using osu.Game.Rulesets.Objects.Types; using System.Collections.Generic; @@ -10,31 +11,32 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// /// A HitObjectParser to parse legacy osu!taiko Beatmaps. /// - internal class HitObjectParser : Legacy.HitObjectParser + internal class ConvertHitObjectParser : Legacy.ConvertHitObjectParser { protected override HitObject CreateHit(Vector2 position, bool newCombo) { - return new Hit + return new ConvertHit { NewCombo = newCombo, }; } - protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount) + protected override HitObject CreateSlider(Vector2 position, bool newCombo, List controlPoints, double length, CurveType curveType, int repeatCount, List> repeatSamples) { - return new Slider + return new ConvertSlider { NewCombo = newCombo, ControlPoints = controlPoints, Distance = length, CurveType = curveType, + RepeatSamples = repeatSamples, RepeatCount = repeatCount }; } protected override HitObject CreateSpinner(Vector2 position, double endTime) { - return new Spinner + return new ConvertSpinner { EndTime = endTime }; diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/Slider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs similarity index 81% rename from osu.Game/Rulesets/Objects/Legacy/Taiko/Slider.cs rename to osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs index 18d2d4039d..b472423a1d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/Slider.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// /// Legacy osu!taiko Slider-type, used for parsing Beatmaps. /// - internal sealed class Slider : CurvedHitObject, IHasCombo + internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasCombo { public bool NewCombo { get; set; } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/Spinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs similarity index 84% rename from osu.Game/Rulesets/Objects/Legacy/Taiko/Spinner.cs rename to osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs index 1b296b9533..abef667d91 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/Spinner.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko /// /// Legacy osu!taiko Spinner-type, used for parsing Beatmaps. /// - internal sealed class Spinner : HitObject, IHasEndTime + internal sealed class ConvertSpinner : HitObject, IHasEndTime { public double EndTime { get; set; } diff --git a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs index 5ff6d03f6d..399138bc24 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasCurve.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasCurve.cs @@ -11,11 +11,6 @@ namespace osu.Game.Rulesets.Objects.Types /// public interface IHasCurve : IHasDistance, IHasRepeats { - /// - /// The curve. - /// - SliderCurve Curve { get; } - /// /// The control points that shape the curve. /// diff --git a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs index f7058fd3c9..2fe2424d49 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasRepeats.cs @@ -1,6 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using osu.Game.Audio; +using System.Collections.Generic; + namespace osu.Game.Rulesets.Objects.Types { /// @@ -12,5 +15,10 @@ namespace osu.Game.Rulesets.Objects.Types /// The amount of times the HitObject repeats. /// int RepeatCount { get; } + + /// + /// The samples to be played when each repeat node is hit (0 -> first repeat node, 1 -> second repeat node, etc). + /// + List> RepeatSamples { get; } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 49cc32a6b6..c9a3b08713 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -109,6 +109,20 @@ + + + + + + + + + + + + + + @@ -124,19 +138,6 @@ - - - - - - - - - - - - - @@ -149,12 +150,11 @@ - - - - - - + + + + + @@ -167,7 +167,7 @@ - +