From 1fa1897d71122d08ad93e8a82be35af6a87d0485 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 15:05:45 +0900 Subject: [PATCH] Define the concept of patterns + additional comments. --- ...Converter.cs => LegacyBeatmapConverter.cs} | 25 +- .../Beatmaps/ManiaBeatmapConverter.cs | 2 +- .../Legacy/DistanceObjectPatternGenerator.cs} | 218 +++++++++--------- .../Legacy/PatternGenerator.cs} | 73 ++---- .../Legacy/PatternType.cs} | 7 +- .../{ObjectList.cs => Patterns/Pattern.cs} | 31 +-- .../Beatmaps/Patterns/PatternGenerator.cs | 89 +++++++ .../osu.Game.Rulesets.Mania.csproj | 11 +- 8 files changed, 255 insertions(+), 201 deletions(-) rename osu.Game.Rulesets.Mania/Beatmaps/{LegacyConverter.cs => LegacyBeatmapConverter.cs} (83%) rename osu.Game.Rulesets.Mania/Beatmaps/{DistanceObjectConversion.cs => Patterns/Legacy/DistanceObjectPatternGenerator.cs} (58%) rename osu.Game.Rulesets.Mania/Beatmaps/{ObjectConversion.cs => Patterns/Legacy/PatternGenerator.cs} (59%) rename osu.Game.Rulesets.Mania/Beatmaps/{LegacyConvertType.cs => Patterns/Legacy/PatternType.cs} (85%) rename osu.Game.Rulesets.Mania/Beatmaps/{ObjectList.cs => Patterns/Pattern.cs} (62%) create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs similarity index 83% rename from osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs rename to osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index 0a85b8c8af..4108ba7809 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -1,32 +1,33 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; +using System; +using System.Collections.Generic; using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; +using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; -using System; -using System.Collections.Generic; -using osu.Game.Rulesets.Mania.MathUtils; +using OpenTK; namespace osu.Game.Rulesets.Mania.Beatmaps { /// /// Special converter used for converting from osu!stable beatmaps. /// - internal class LegacyConverter + internal class LegacyBeatmapConverter { private readonly FastRandom random; - private ObjectList lastRow = new ObjectList(); + private Patterns.Pattern lastPattern = new Patterns.Pattern(); private readonly int availableColumns; private readonly float localXDivisor; private readonly Beatmap beatmap; - public LegacyConverter(Beatmap beatmap) + public LegacyBeatmapConverter(Beatmap beatmap) { this.beatmap = beatmap; @@ -93,10 +94,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var distanceData = original as IHasDistance; var positionData = original as IHasPosition; - ObjectConversion conversion = null; + Patterns.PatternGenerator conversion = null; if (distanceData != null) - conversion = new DistanceObjectConversion(original, lastRow, random, beatmap); + conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern); else if (endTimeData != null) { // Spinner @@ -109,12 +110,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps if (conversion == null) yield break; - ObjectList newRow = conversion.Generate(); + Patterns.Pattern newPattern = conversion.Generate(); - foreach (ManiaHitObject obj in newRow.HitObjects) + foreach (ManiaHitObject obj in newPattern.HitObjects) yield return obj; - lastRow = newRow; + lastPattern = newPattern; } private int getColumn(float position) => MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, availableColumns - 1); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 37150adb66..aea77cd2b5 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps protected override Beatmap ConvertBeatmap(Beatmap original) { // Todo: This should be cased when we get better conversion methods - var converter = new LegacyConverter(original); + var converter = new LegacyBeatmapConverter(original); return new Beatmap { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs similarity index 58% rename from osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs rename to osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 59d4a7a80c..03240a2be4 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -1,50 +1,49 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Timing; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; using System; -using osu.Game.Rulesets.Mania.MathUtils; using System.Linq; using osu.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; -namespace osu.Game.Rulesets.Mania.Beatmaps +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { - internal class DistanceObjectConversion : ObjectConversion + /// + /// A pattern generator for IHasDistance hit objects. + /// + internal class DistanceObjectPatternGenerator : PatternGenerator { /// /// Base osu! slider scoring distance. /// private const float osu_base_scoring_distance = 100; - private readonly HitObject originalObject; - private readonly double endTime; private readonly int repeatCount; - private LegacyConvertType convertType; + private PatternType convertType; - public DistanceObjectConversion(HitObject originalObject, ObjectList previousObjects, FastRandom random, Beatmap beatmap) - : base(previousObjects, random, beatmap) + public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(random, hitObject, beatmap, previousPattern) { - this.originalObject = originalObject; - ControlPoint overridePoint; - ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(originalObject.StartTime, out overridePoint); + ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint); - convertType = LegacyConvertType.None; + convertType = PatternType.None; if ((overridePoint ?? controlPoint)?.KiaiMode == false) - convertType = LegacyConvertType.LowProbability; + convertType = PatternType.LowProbability; - var distanceData = originalObject as IHasDistance; - var repeatsData = originalObject as IHasRepeats; + var distanceData = hitObject as IHasDistance; + var repeatsData = hitObject as IHasRepeats; repeatCount = repeatsData?.RepeatCount ?? 1; - double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(originalObject.StartTime); - double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(originalObject.StartTime) * speedAdjustment; + double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(hitObject.StartTime); + double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(hitObject.StartTime) * speedAdjustment; // The true distance, accounting for any repeats. This ends up being the drum roll distance later double distance = distanceData.Distance * repeatCount; @@ -54,73 +53,73 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // The duration of the osu! hit object double osuDuration = distance / osuVelocity; - endTime = originalObject.StartTime + osuDuration; + endTime = hitObject.StartTime + osuDuration; } - public override ObjectList Generate() + public override Pattern Generate() { double segmentDuration = endTime / repeatCount; if (repeatCount > 1) { if (segmentDuration <= 90) - return generateRandomHoldNotes(originalObject.StartTime, endTime, 1); + return generateRandomHoldNotes(HitObject.StartTime, endTime, 1); if (segmentDuration <= 120) { - convertType |= LegacyConvertType.ForceNotStack; - return generateRandomNotes(originalObject.StartTime, segmentDuration, repeatCount); + convertType |= PatternType.ForceNotStack; + return generateRandomNotes(HitObject.StartTime, segmentDuration, repeatCount); } if (segmentDuration <= 160) - return generateStair(originalObject.StartTime, segmentDuration, repeatCount); + return generateStair(HitObject.StartTime, segmentDuration); if (segmentDuration <= 200 && ConversionDifficulty > 3) - return generateRandomMultipleNotes(originalObject.StartTime, segmentDuration, repeatCount); + return generateRandomMultipleNotes(HitObject.StartTime, segmentDuration, repeatCount); - double duration = endTime - originalObject.StartTime; + double duration = endTime - HitObject.StartTime; if (duration >= 4000) - return generateNRandomNotes(originalObject.StartTime, endTime, 0.23, 0, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.23, 0, 0); if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) - return generateTiledHoldNotes(originalObject.StartTime, segmentDuration, repeatCount); + return generateTiledHoldNotes(HitObject.StartTime, segmentDuration, repeatCount); - return generateHoldAndNormalNotes(originalObject.StartTime, segmentDuration); + return generateHoldAndNormalNotes(HitObject.StartTime, segmentDuration); } if (segmentDuration <= 110) { - if (PreviousObjects.ColumnsFilled < AvailableColumns) - convertType |= LegacyConvertType.ForceNotStack; + if (PreviousPattern.ColumnsFilled < AvailableColumns) + convertType |= PatternType.ForceNotStack; else - convertType &= ~LegacyConvertType.ForceNotStack; - return generateRandomNotes(originalObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); + convertType &= ~PatternType.ForceNotStack; + return generateRandomNotes(HitObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); } if (ConversionDifficulty > 6.5) { - if ((convertType & LegacyConvertType.LowProbability) > 0) - return generateNRandomNotes(originalObject.StartTime, endTime, 0.78, 0.3, 0); - return generateNRandomNotes(originalObject.StartTime, endTime, 0.85, 0.36, 0.03); + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.78, 0.3, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.85, 0.36, 0.03); } if (ConversionDifficulty > 4) { - if ((convertType & LegacyConvertType.LowProbability) > 0) - return generateNRandomNotes(originalObject.StartTime, endTime, 0.43, 0.08, 0); - return generateNRandomNotes(originalObject.StartTime, endTime, 0.56, 0.18, 0); + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.43, 0.08, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.56, 0.18, 0); } if (ConversionDifficulty > 2.5) { - if ((convertType & LegacyConvertType.LowProbability) > 0) - return generateNRandomNotes(originalObject.StartTime, endTime, 0.3, 0, 0); - return generateNRandomNotes(originalObject.StartTime, endTime, 0.37, 0.08, 0); + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.3, 0, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.37, 0.08, 0); } - if ((convertType & LegacyConvertType.LowProbability) > 0) - return generateNRandomNotes(originalObject.StartTime, endTime, 0.17, 0, 0); - return generateNRandomNotes(originalObject.StartTime, endTime, 0.27, 0, 0); + if ((convertType & PatternType.LowProbability) > 0) + return generateNRandomNotes(HitObject.StartTime, endTime, 0.17, 0, 0); + return generateNRandomNotes(HitObject.StartTime, endTime, 0.27, 0, 0); } /// @@ -129,34 +128,34 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// Start time of each hold note. /// End time of the hold notes. /// Number of hold notes. - /// The containing the hit objects. - private ObjectList generateRandomHoldNotes(double startTime, double endTime, int noteCount) + /// The containing the hit objects. + private Pattern generateRandomHoldNotes(double startTime, double endTime, int noteCount) { // - - - - // ■ - ■ ■ // □ - □ □ // ■ - ■ ■ - var newObjects = new ObjectList(); + var pattern = new Pattern(); - int usableColumns = AvailableColumns - RandomStart - PreviousObjects.ColumnsFilled; + int usableColumns = AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled; int nextColumn = Random.Next(RandomStart, AvailableColumns); for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) { - while (newObjects.IsFilled(nextColumn) || PreviousObjects.IsFilled(nextColumn)) //find available column + while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); - Add(newObjects, originalObject, nextColumn, startTime, endTime, noteCount); + AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); } // This is can't be combined with the above loop due to RNG for (int i = 0; i < noteCount - usableColumns; i++) { - while (newObjects.IsFilled(nextColumn)) + while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - Add(newObjects, originalObject, nextColumn, startTime, endTime, noteCount); + AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); } - return newObjects; + return pattern; } /// @@ -165,8 +164,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// The start time. /// The separation of notes between rows. /// The number of rows. - /// The containing the hit objects. - private ObjectList generateRandomNotes(double startTime, double separationTime, int repeatCount) + /// The containing the hit objects. + private Pattern generateRandomNotes(double startTime, double separationTime, int repeatCount) { // - - - - // x - - - @@ -174,19 +173,19 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // - - - x // x - - - - var newObjects = new ObjectList(); + var pattern = new Pattern(); - int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousObjects.ColumnsFilled < AvailableColumns) + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) { - while (PreviousObjects.IsFilled(nextColumn)) + while (PreviousPattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); } int lastColumn = nextColumn; for (int i = 0; i <= repeatCount; i++) { - Add(newObjects, originalObject, nextColumn, startTime, startTime); + AddToPattern(pattern, HitObject, nextColumn, startTime, startTime); while (nextColumn == lastColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); @@ -194,7 +193,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps startTime += separationTime; } - return newObjects; + return pattern; } /// @@ -202,9 +201,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The start time. /// The separation of notes between rows. - /// The number of rows/notes. - /// The containing the hit objects. - private ObjectList generateStair(double startTime, double separationTime, int repeatCount) + /// The containing the hit objects. + private Pattern generateStair(double startTime, double separationTime) { // - - - - // x - - - @@ -215,14 +213,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // - x - - // x - - - - var newObjects = new ObjectList(); + var pattern = new Pattern(); - int column = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); bool increasing = Random.NextDouble() > 0.5; for (int i = 0; i <= repeatCount; i++) { - Add(newObjects, originalObject, column, startTime, startTime); + AddToPattern(pattern, HitObject, column, startTime, startTime); startTime += separationTime; // Check if we're at the borders of the stage, and invert the pattern if so @@ -248,7 +246,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } } - return newObjects; + return pattern; } /// @@ -257,8 +255,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// The start time. /// The separation of notes between rows. /// The number of rows. - /// The containing the hit objects. - private ObjectList generateRandomMultipleNotes(double startTime, double separationTime, int repeatCount) + /// The containing the hit objects. + private Pattern generateRandomMultipleNotes(double startTime, double separationTime, int repeatCount) { // - - - - // x - - @@ -266,15 +264,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // - - - x // x - x - - var newObjects = new ObjectList(); + var pattern = new Pattern(); bool legacy = AvailableColumns >= 4 && AvailableColumns <= 8; int interval = Random.Next(1, AvailableColumns - (legacy ? 1 : 0)); - int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i <= repeatCount; i++) { - Add(newObjects, originalObject, nextColumn, startTime, startTime, 2); + AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); nextColumn += interval; if (nextColumn >= AvailableColumns - RandomStart) @@ -283,13 +281,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // If we're in 2K, let's not add many consecutive doubles if (AvailableColumns > 2) - Add(newObjects, originalObject, nextColumn, startTime, startTime, 2); + AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); nextColumn = Random.Next(RandomStart, AvailableColumns); startTime += separationTime; } - return newObjects; + return pattern; } /// @@ -300,8 +298,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// The probability required for 2 hold notes to be generated. /// The probability required for 3 hold notes to be generated. /// The probability required for 4 hold notes to be generated. - /// The containing the hit objects. - private ObjectList generateNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) + /// The containing the hit objects. + private Pattern generateNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) { // - - - - // ■ - ■ ■ @@ -334,8 +332,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps Func isDoubleSample = sample => sample.Name == SampleInfo.HIT_CLAP && sample.Name == SampleInfo.HIT_FINISH; - bool canGenerateTwoNotes = (convertType & LegacyConvertType.LowProbability) == 0; - canGenerateTwoNotes &= originalObject.Samples.Any(isDoubleSample) || sampleInfoListAt(originalObject.StartTime).Any(isDoubleSample); + bool canGenerateTwoNotes = (convertType & PatternType.LowProbability) == 0; + canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample); if (canGenerateTwoNotes) p2 = 1; @@ -349,8 +347,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// The first hold note start time. /// The separation time between hold notes. /// The amount of hold notes. - /// The containing the hit objects. - private ObjectList generateTiledHoldNotes(double startTime, double separationTime, int noteCount) + /// The containing the hit objects. + private Pattern generateTiledHoldNotes(double startTime, double separationTime, int noteCount) { // - - - - // ■ ■ ■ ■ @@ -361,27 +359,27 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // □ ■ - - // ■ - - - - var newObjects = new ObjectList(); + var pattern = new Pattern(); int columnRepeat = Math.Min(noteCount, AvailableColumns); - int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousObjects.ColumnsFilled < AvailableColumns) + int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) { - while (PreviousObjects.IsFilled(nextColumn)) + while (PreviousPattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); } for (int i = 0; i < columnRepeat; i++) { - while (newObjects.IsFilled(nextColumn)) + while (pattern.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - Add(newObjects, originalObject, nextColumn, startTime, endTime, noteCount); + AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); startTime += separationTime; } - return newObjects; + return pattern; } /// @@ -389,8 +387,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The start time of notes. /// The separation time between notes. - /// The containing the hit objects. - private ObjectList generateHoldAndNormalNotes(double startTime, double separationTime) + /// The containing the hit objects. + private Pattern generateHoldAndNormalNotes(double startTime, double separationTime) { // - - - - // ■ x x - @@ -398,17 +396,17 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // ■ x - x // ■ - x x - var newObjects = new ObjectList(); + var pattern = new Pattern(); - int holdColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousObjects.ColumnsFilled < AvailableColumns) + int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) { - while (PreviousObjects.IsFilled(holdColumn)) + while (PreviousPattern.IsFilled(holdColumn)) holdColumn = Random.Next(RandomStart, AvailableColumns); } // Create the hold note - Add(newObjects, originalObject, holdColumn, startTime, separationTime * repeatCount); + AddToPattern(pattern, HitObject, holdColumn, startTime, separationTime * repeatCount); int noteCount = 1; if (ConversionDifficulty > 6.5) @@ -422,26 +420,26 @@ namespace osu.Game.Rulesets.Mania.Beatmaps bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); int nextColumn = Random.Next(RandomStart, AvailableColumns); - var tempObjects = new ObjectList(); + var rowPattern = new Pattern(); for (int i = 0; i <= repeatCount; i++) { - if (!(ignoreHead && startTime == originalObject.StartTime)) + if (!(ignoreHead && startTime == HitObject.StartTime)) { for (int j = 0; j < noteCount; j++) { - while (tempObjects.IsFilled(nextColumn) || nextColumn == holdColumn) + while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); - Add(tempObjects, originalObject, nextColumn, startTime, startTime, noteCount + 1); + AddToPattern(rowPattern, HitObject, nextColumn, startTime, startTime, noteCount + 1); } } - newObjects.Add(tempObjects); - tempObjects.Clear(); + pattern.Add(rowPattern); + rowPattern.Clear(); startTime += separationTime; } - return newObjects; + return pattern; } /// @@ -451,14 +449,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// private SampleInfoList sampleInfoListAt(double time) { - var curveData = originalObject as IHasCurve; + var curveData = HitObject as IHasCurve; if (curveData == null) - return originalObject.Samples; + return HitObject.Samples; - double segmentTime = (curveData.EndTime - originalObject.StartTime) / repeatCount; + double segmentTime = (curveData.EndTime - HitObject.StartTime) / repeatCount; - int index = (int)(segmentTime == 0 ? 0 : (time - originalObject.StartTime) / segmentTime); + int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); return curveData.RepeatSamples[index]; } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs similarity index 59% rename from osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs rename to osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index 83c0af9d46..ad07c03b96 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -1,42 +1,39 @@ // 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.Beatmaps; -using osu.Game.Rulesets.Mania.MathUtils; using System; using System.Linq; +using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Objects; +using OpenTK; -namespace osu.Game.Rulesets.Mania.Beatmaps +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { - internal abstract class ObjectConversion + /// + /// A pattern generator for legacy hit objects. + /// + internal abstract class PatternGenerator : Patterns.PatternGenerator { - protected readonly int AvailableColumns; + /// + /// The column index at which to start generating random notes. + /// protected readonly int RandomStart; - protected ObjectList PreviousObjects; + /// + /// The random number generator to use. + /// protected readonly FastRandom Random; - protected readonly Beatmap Beatmap; - protected ObjectConversion(ObjectList previousObjects, FastRandom random, Beatmap beatmap) + protected PatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(hitObject, beatmap, previousPattern) { - PreviousObjects = previousObjects; Random = random; - Beatmap = beatmap; - AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); RandomStart = AvailableColumns == 8 ? 1 : 0; } - /// - /// Generates a new object list filled with converted hit objects. - /// - /// The containing the hit objects. - public abstract ObjectList Generate(); - /// /// Converts an x-position into a column. /// @@ -78,44 +75,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return val >= 1 - p2 ? 2 : 1; } - /// - /// Constructs and adds a note to an object list. - /// - /// The list to add to. - /// The original hit object (used for samples). - /// The column to add the note to. - /// The start time of the note. - /// The end time of the note (set to for a non-hold note). - /// The number of children alongside this note (these will not be generated, but are used for volume calculations). - protected void Add(ObjectList objectList, HitObject originalObject, int column, double startTime, double endTime, int siblings = 1) - { - ManiaHitObject newObject; - - if (startTime == endTime) - { - newObject = new Note - { - StartTime = startTime, - Samples = originalObject.Samples, - Column = column - }; - } - else - { - newObject = new HoldNote - { - StartTime = startTime, - Samples = originalObject.Samples, - Column = column, - Duration = endTime - startTime - }; - } - - // Todo: Consider siblings and write sample volumes (probably at ManiaHitObject level) - - objectList.Add(newObject); - } - private double? conversionDifficulty; /// /// A difficulty factor used for various conversion methods from osu!stable. diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs similarity index 85% rename from osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs rename to osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs index 086bc89292..d4957d41a9 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternType.cs @@ -3,10 +3,13 @@ using System; -namespace osu.Game.Rulesets.Mania.Beatmaps +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy { + /// + /// The type of pattern to generate. Used for legacy patterns. + /// [Flags] - internal enum LegacyConvertType + internal enum PatternType { None = 0, /// diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectList.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs similarity index 62% rename from osu.Game.Rulesets.Mania/Beatmaps/ObjectList.cs rename to osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs index 13bb32a113..cbde1f0f53 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ObjectList.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Pattern.cs @@ -1,56 +1,59 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Game.Rulesets.Mania.Objects; using System.Collections.Generic; using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Rulesets.Mania.Objects; -namespace osu.Game.Rulesets.Mania.Beatmaps +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns { - internal class ObjectList + /// + /// Creates a pattern containing hit objects. + /// + internal class Pattern { private readonly List hitObjects = new List(); /// - /// All the hit objects contained in this list. + /// All the hit objects contained in this pattern. /// public IEnumerable HitObjects => hitObjects; /// - /// Whether a column of this list has been taken. + /// Whether this pattern already contains a hit object in a code. /// /// The column index. - /// Whether the column already contains a hit object. + /// Whether this pattern already contains a hit object in public bool IsFilled(int column) => hitObjects.Exists(h => h.Column == column); /// - /// Amount of columns taken up by hit objects in this list. + /// Amount of columns taken up by hit objects in this pattern. /// public int ColumnsFilled => HitObjects.GroupBy(h => h.Column).Count(); /// - /// Adds a hit object to this list. + /// Adds a hit object to this pattern. /// /// The hit object to add. public void Add(ManiaHitObject hitObject) => hitObjects.Add(hitObject); /// - /// Copies hit object from another list to this one. + /// Copies hit object from another pattern to this one. /// - /// The other list. - public void Add(ObjectList other) + /// The other pattern. + public void Add(Pattern other) { other.HitObjects.ForEach(Add); } /// - /// Clears this list. + /// Clears this pattern, removing all hit objects. /// public void Clear() => hitObjects.Clear(); /// - /// Removes a hit object from this list. + /// Removes a hit object from this pattern. /// /// The hit object to remove. public bool Remove(ManiaHitObject hitObject) => hitObjects.Remove(hitObject); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs new file mode 100644 index 0000000000..81aeb48c01 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs @@ -0,0 +1,89 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns +{ + /// + /// Generator to create a pattern from a hit object. + /// + internal abstract class PatternGenerator + { + /// + /// The number of columns available to create the pattern. + /// + protected readonly int AvailableColumns; + + /// + /// The last pattern. + /// + protected readonly Pattern PreviousPattern; + + /// + /// The hit object to create the pattern for. + /// + protected readonly HitObject HitObject; + + /// + /// The beatmap which is a part of. + /// + protected readonly Beatmap Beatmap; + + protected PatternGenerator(HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + { + PreviousPattern = previousPattern; + HitObject = hitObject; + Beatmap = beatmap; + + AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); + } + + /// + /// Generates the pattern for , filled with hit objects. + /// + /// The containing the hit objects. + public abstract Pattern Generate(); + + /// + /// Constructs and adds a note to a pattern. + /// + /// The pattern to add to. + /// The original hit object (used for samples). + /// The column to add the note to. + /// The start time of the note. + /// The end time of the note (set to for a non-hold note). + /// The number of children alongside this note (these will not be generated, but are used for volume calculations). + protected void AddToPattern(Pattern pattern, HitObject originalObject, int column, double startTime, double endTime, int siblings = 1) + { + ManiaHitObject newObject; + + if (startTime == endTime) + { + newObject = new Note + { + StartTime = startTime, + Samples = originalObject.Samples, + Column = column + }; + } + else + { + newObject = new HoldNote + { + StartTime = startTime, + Samples = originalObject.Samples, + Column = column, + Duration = endTime - startTime + }; + } + + // Todo: Consider siblings and write sample volumes (probably at ManiaHitObject level) + + pattern.Add(newObject); + } + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 3d93dd3068..9de9cd703f 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,12 +47,13 @@ - - - - + + + + + - +