From 51f7904c137aaf8bec05cd468306d53f4729aac1 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 17 May 2017 13:04:34 +0900 Subject: [PATCH 01/34] Remove redundant parentheses. --- osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs | 4 ++-- osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs index d090fbb0a0..381e24c84c 100644 --- a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs +++ b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs @@ -33,11 +33,11 @@ namespace osu.Game.Rulesets.Mania.MathUtils /// The random value. public uint NextUInt() { - uint t = (_x ^ (_x << 11)); + uint t = _x ^ _x << 11; _x = _y; _y = _z; _z = _w; - return (_w = (_w ^ (_w >> 19)) ^ (t ^ (t >> 8))); + return _w = _w ^ _w >> 19 ^ t ^ t >> 8; } /// diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index 986aefb2bd..da4a693dd8 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.Mania.MathUtils; namespace osu.Game.Rulesets.Mania.UI { @@ -27,6 +28,11 @@ namespace osu.Game.Rulesets.Mania.UI public ManiaHitRenderer(WorkingBeatmap beatmap) : base(beatmap) { + FastRandom fr = new FastRandom(1337); + while (true) + { + int value = fr.Next(); + } } protected override Playfield CreatePlayfield() From 1ded04377815f3b0ef926982f2f2c93afb7a1d2f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 17 May 2017 13:07:56 +0900 Subject: [PATCH 02/34] Add basic mania-specific beatmap conversion. # Conflicts: # osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs --- .../Beatmaps/LegacyConverter.cs | 72 +++++++++++++++++++ .../Beatmaps/ManiaBeatmapConverter.cs | 41 ++++++----- .../osu.Game.Rulesets.Mania.csproj | 1 + 3 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs new file mode 100644 index 0000000000..20a3dc612b --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -0,0 +1,72 @@ +// 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.Objects; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using SharpNeat.Utility; +using System; +using System.Collections.Generic; + +namespace osu.Game.Rulesets.Mania.Beatmaps +{ + /// + /// Special converter used for converting from osu!stable beatmaps. + /// + internal class LegacyConverter + { + private readonly FastRandom random; + + private readonly int availableColumns; + private readonly float localXDivisor; + + private readonly Beatmap beatmap; + + public LegacyConverter(Beatmap beatmap) + { + this.beatmap = beatmap; + + int seed = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.DrainRate + beatmap.BeatmapInfo.Difficulty.CircleSize) + * 20 + (int)(beatmap.BeatmapInfo.Difficulty.OverallDifficulty * 41.2) + (int)Math.Round(beatmap.BeatmapInfo.Difficulty.ApproachRate); + + availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); + localXDivisor = 512.0f / availableColumns; + } + + public IEnumerable Convert(HitObject original) + { + if (beatmap.BeatmapInfo.RulesetID == 3) + yield return generateSpecific(original); + } + + private ManiaHitObject generateSpecific(HitObject original) + { + var endTimeData = original as IHasEndTime; + var positionData = original as IHasPosition; + + int column = getColumn(positionData?.X ?? 0); + + if (endTimeData != null) + { + return new HoldNote + { + StartTime = original.StartTime, + Samples = original.Samples, + Duration = endTimeData.Duration, + Column = column, + }; + } + + return new Note + { + StartTime = original.StartTime, + Samples = original.Samples, + Column = column + }; + } + + 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 e51bbcdc13..e9dae95782 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -1,35 +1,38 @@ // 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.Rulesets.Mania.Objects; -using System.Collections.Generic; -using System; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using System; +using System.Collections.Generic; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; -using OpenTK; +using osu.Game.Rulesets.Objects.Types; +using System.Linq; namespace osu.Game.Rulesets.Mania.Beatmaps { - internal class ManiaBeatmapConverter : BeatmapConverter + public class ManiaBeatmapConverter : BeatmapConverter { protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; + protected override Beatmap ConvertBeatmap(Beatmap original) + { + // Todo: This should be cased when we get better conversion methods + var converter = new LegacyConverter(original); + + return new Beatmap + { + BeatmapInfo = original.BeatmapInfo, + TimingInfo = original.TimingInfo, + HitObjects = original.HitObjects.SelectMany(converter.Convert).ToList() + }; + } + protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { - int availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); - - var positionData = original as IHasXPosition; - - float localWDivisor = 512.0f / availableColumns; - int column = MathHelper.Clamp((int)Math.Floor((positionData?.X ?? 1) / localWDivisor), 0, availableColumns - 1); - - yield return new Note - { - StartTime = original.StartTime, - Column = column, - }; + // Handled by the LegacyConvereter + yield return null; } } } diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 52396debf5..781dc3e228 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,6 +47,7 @@ + From fdd98e23bdf315e1f7071fb21dd1cdc6b5dc99ed Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 12 May 2017 16:12:18 +0900 Subject: [PATCH 03/34] Fix generation. --- osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index 20a3dc612b..3d3b052ce6 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private ManiaHitObject generateSpecific(HitObject original) { var endTimeData = original as IHasEndTime; - var positionData = original as IHasPosition; + var positionData = original as IHasXPosition; int column = getColumn(positionData?.X ?? 0); From 17466a662cb98fbbd10caef177619e34be3a6c10 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 12 May 2017 16:35:57 +0900 Subject: [PATCH 04/34] Add hold note conversion. --- .../UI/ManiaHitRenderer.cs | 4 +++ .../Legacy/Catch/ConvertHitObjectParser.cs | 5 ++++ .../Objects/Legacy/ConvertHitObjectParser.cs | 29 +++++++++++++------ .../Rulesets/Objects/Legacy/ConvertHold.cs | 22 -------------- .../Legacy/Mania/ConvertHitObjectParser.cs | 9 ++++++ .../Objects/Legacy/Mania/ConvertHold.cs | 16 ++++++++++ .../Legacy/Osu/ConvertHitObjectParser.cs | 5 ++++ .../Legacy/Taiko/ConvertHitObjectParser.cs | 5 ++++ osu.Game/Rulesets/Objects/Types/IHasHold.cs | 4 +++ osu.Game/osu.Game.csproj | 2 +- 10 files changed, 69 insertions(+), 32 deletions(-) delete mode 100644 osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs create mode 100644 osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index da4a693dd8..9387b8e9cb 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -82,6 +82,10 @@ namespace osu.Game.Rulesets.Mania.UI protected override DrawableHitObject GetVisualRepresentation(ManiaHitObject h) { + var holdNote = h as HoldNote; + if (holdNote != null) + return new DrawableHoldNote(holdNote); + var note = h as Note; if (note != null) return new DrawableNote(note); diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs index 5c534456ef..c7f7802191 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHitObjectParser.cs @@ -43,5 +43,10 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch EndTime = endTime }; } + + protected override HitObject CreateHold(Vector2 position, bool newCombo, double endTime) + { + return null; + } } } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index c5551082ec..3b2d7211bb 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Globalization; using osu.Game.Beatmaps.Formats; using osu.Game.Audio; +using System.Linq; namespace osu.Game.Rulesets.Objects.Legacy { @@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Objects.Legacy var soundType = (LegacySoundType)int.Parse(split[4]); var bankInfo = new SampleBankInfo(); - HitObject result; + HitObject result = null; if ((type & ConvertHitObjectType.Circle) > 0) { @@ -140,17 +141,19 @@ namespace osu.Game.Rulesets.Objects.Legacy { // Note: Hold is generated by BMS converts - // Todo: Apparently end time is determined by samples?? - // Shouldn't need implementation until mania + double endTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); - result = new ConvertHold + if (split.Length > 5 && !string.IsNullOrEmpty(split[5])) { - Position = new Vector2(int.Parse(split[0]), int.Parse(split[1])), - NewCombo = combo - }; + endTime = Convert.ToDouble(split[0], CultureInfo.InvariantCulture); + readCustomSampleBanks(string.Join(":", split.Skip(1)), bankInfo); + } + + result = CreateHold(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, endTime); } - else - throw new InvalidOperationException($@"Unknown hit object type {type}"); + + if (result == null) + throw new InvalidOperationException($@"Unknown hit object type {type}."); result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture); result.Samples = convertSoundType(soundType, bankInfo); @@ -214,6 +217,14 @@ namespace osu.Game.Rulesets.Objects.Legacy /// The hit object. protected abstract HitObject CreateSpinner(Vector2 position, double endTime); + /// + /// Creates a legacy Hold-type hit object. + /// + /// The position of the hit object. + /// Whether the hit object creates a new combo. + /// The hold end time. + protected abstract HitObject CreateHold(Vector2 position, bool newCombo, double endTime); + private SampleInfoList convertSoundType(LegacySoundType type, SampleBankInfo bankInfo) { var soundTypes = new SampleInfoList diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs deleted file mode 100644 index d79f6e324e..0000000000 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHold.cs +++ /dev/null @@ -1,22 +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; - -namespace osu.Game.Rulesets.Objects.Legacy -{ - /// - /// Legacy Hold-type, used for parsing "specials" in beatmaps. - /// - internal sealed class ConvertHold : HitObject, IHasPosition, IHasCombo, IHasHold - { - public Vector2 Position { get; set; } - - public float X => Position.X; - - public float Y => Position.Y; - - public bool NewCombo { get; set; } - } -} diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs index 224f068323..7141876b8b 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHitObjectParser.cs @@ -44,5 +44,14 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania EndTime = endTime }; } + + protected override HitObject CreateHold(Vector2 position, bool newCombo, double endTime) + { + return new ConvertHold + { + X = position.X, + EndTime = endTime + }; + } } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs new file mode 100644 index 0000000000..1dda577320 --- /dev/null +++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs @@ -0,0 +1,16 @@ +// 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; + +namespace osu.Game.Rulesets.Objects.Legacy.Mania +{ + internal sealed class ConvertHold : HitObject, IHasXPosition, IHasEndTime + { + public float X { get; set; } + + public double EndTime { get; set; } + + public double Duration => EndTime - StartTime; + } +} diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs index 41bf142831..00fe171f0f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHitObjectParser.cs @@ -44,5 +44,10 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu EndTime = endTime }; } + + protected override HitObject CreateHold(Vector2 position, bool newCombo, double endTime) + { + return null; + } } } diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs index 0d755d7527..5929c5a907 100644 --- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHitObjectParser.cs @@ -41,5 +41,10 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko EndTime = endTime }; } + + protected override HitObject CreateHold(Vector2 position, bool newCombo, double endTime) + { + return null; + } } } diff --git a/osu.Game/Rulesets/Objects/Types/IHasHold.cs b/osu.Game/Rulesets/Objects/Types/IHasHold.cs index 82ec790524..4054fc4fd1 100644 --- a/osu.Game/Rulesets/Objects/Types/IHasHold.cs +++ b/osu.Game/Rulesets/Objects/Types/IHasHold.cs @@ -8,5 +8,9 @@ namespace osu.Game.Rulesets.Objects.Types /// public interface IHasHold { + /// + /// The time at which the hold ends. + /// + double EndTime { get; } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 63acdb1914..9352cfba6e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -125,6 +125,7 @@ + @@ -161,7 +162,6 @@ - From 9565bb9572a80aeb4cf8ef32c23b92d4b583e3f7 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 12 May 2017 19:10:26 +0900 Subject: [PATCH 05/34] Fix hold notes - remove glow for now. # Conflicts: # osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs # osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs --- .../Tests/TestCaseManiaHitObjects.cs | 14 +++------- .../Objects/Drawables/DrawableHoldNote.cs | 11 ++++++++ .../Drawables/DrawableManiaHitObject.cs | 26 ------------------- .../Objects/Drawables/Pieces/BodyPiece.cs | 1 - .../Objects/Legacy/ConvertHitObjectParser.cs | 5 ++-- 5 files changed, 17 insertions(+), 40 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs b/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs index 3ad83beb73..3113b63db1 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseManiaHitObjects.cs @@ -43,13 +43,8 @@ namespace osu.Desktop.VisualTests.Tests RelativeCoordinateSpace = new Vector2(1, 10000), Children = new[] { - new DrawableNote(new Note - { - StartTime = 5000 - }) - { - AccentColour = Color4.Red - } + new DrawableNote(new Note { StartTime = 5000 }) { AccentColour = Color4.Red }, + new DrawableNote(new Note { StartTime = 6000 }) { AccentColour = Color4.Red } } } } @@ -74,10 +69,7 @@ namespace osu.Desktop.VisualTests.Tests { StartTime = 5000, Duration = 1000 - }) - { - AccentColour = Color4.Red - } + }) { AccentColour = Color4.Red } } } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 767a2b3458..a1327a3105 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -61,5 +61,16 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected override void UpdateState(ArmedState state) { } + + protected override void Update() + { + if (Time.Current > HitObject.StartTime) + headPiece.Colour = Color4.Green; + if (Time.Current > HitObject.EndTime) + { + bodyPiece.Colour = Color4.Green; + tailPiece.Colour = Color4.Green; + } + } } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 0307e9162a..d33a8c48ee 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -3,8 +3,6 @@ using OpenTK.Graphics; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Mania.Judgements; using osu.Game.Rulesets.Objects.Drawables; @@ -15,8 +13,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { public new TObject HitObject; - private readonly Container glowContainer; - protected DrawableManiaHitObject(TObject hitObject) : base(hitObject) { @@ -24,21 +20,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables RelativePositionAxes = Axes.Y; Y = (float)HitObject.StartTime; - - Add(glowContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - }); } public override Color4 AccentColour @@ -49,13 +30,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables if (base.AccentColour == value) return; base.AccentColour = value; - - glowContainer.EdgeEffect = new EdgeEffect - { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = value - }; } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs index ce61a7a86f..c10aa9994b 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs @@ -19,7 +19,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces public BodyPiece() { RelativeSizeAxes = Axes.Both; - Masking = true; Children = new[] { diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 3b2d7211bb..a4c319291c 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -145,8 +145,9 @@ namespace osu.Game.Rulesets.Objects.Legacy if (split.Length > 5 && !string.IsNullOrEmpty(split[5])) { - endTime = Convert.ToDouble(split[0], CultureInfo.InvariantCulture); - readCustomSampleBanks(string.Join(":", split.Skip(1)), bankInfo); + string[] ss = split[5].Split(':'); + endTime = Convert.ToDouble(ss[0], CultureInfo.InvariantCulture); + readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo); } result = CreateHold(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, endTime); From 4d9aea6aecefb0287b78ffeaaaed798e25401228 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 17 May 2017 13:14:42 +0900 Subject: [PATCH 06/34] Remove while statement (came from fastrandom...). --- osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index 9387b8e9cb..3c31c6b854 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -17,7 +17,6 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; -using osu.Game.Rulesets.Mania.MathUtils; namespace osu.Game.Rulesets.Mania.UI { @@ -28,11 +27,6 @@ namespace osu.Game.Rulesets.Mania.UI public ManiaHitRenderer(WorkingBeatmap beatmap) : base(beatmap) { - FastRandom fr = new FastRandom(1337); - while (true) - { - int value = fr.Next(); - } } protected override Playfield CreatePlayfield() From 2f8556a44a36a88041f5efc7fc380e6a98c9b99f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 17 May 2017 13:20:33 +0900 Subject: [PATCH 07/34] Fix hold notes + make it compile again. --- osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs | 2 +- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index 3d3b052ce6..544f396f4a 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -6,9 +6,9 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; -using SharpNeat.Utility; using System; using System.Collections.Generic; +using osu.Game.Rulesets.Mania.MathUtils; namespace osu.Game.Rulesets.Mania.Beatmaps { diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index a1327a3105..d9e46f4720 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables tailPiece = new NotePiece { Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre + Origin = Anchor.TopCentre } }); } From 74c23ff6d8a4f110993141266070a8ed843b85ee Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 17 May 2017 18:42:48 +0900 Subject: [PATCH 08/34] Add base for event parsing code. --- osu.Game/Beatmaps/Beatmap.cs | 3 + .../{EventType.cs => BackgroundEvent.cs} | 15 ++--- osu.Game/Beatmaps/Events/BreakEvent.cs | 28 +++++++++ osu.Game/Beatmaps/Events/Event.cs | 13 ++++ osu.Game/Beatmaps/Events/EventInfo.cs | 26 ++++++++ osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs | 59 +++++++++++++++---- osu.Game/osu.Game.csproj | 5 +- 7 files changed, 126 insertions(+), 23 deletions(-) rename osu.Game/Beatmaps/Events/{EventType.cs => BackgroundEvent.cs} (52%) create mode 100644 osu.Game/Beatmaps/Events/BreakEvent.cs create mode 100644 osu.Game/Beatmaps/Events/Event.cs create mode 100644 osu.Game/Beatmaps/Events/EventInfo.cs diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 3964fd25a7..a64002e0b0 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using OpenTK.Graphics; +using osu.Game.Beatmaps.Events; using osu.Game.Beatmaps.Timing; using osu.Game.Database; using osu.Game.Rulesets.Objects; @@ -17,6 +18,7 @@ namespace osu.Game.Beatmaps { public BeatmapInfo BeatmapInfo; public TimingInfo TimingInfo = new TimingInfo(); + public EventInfo EventInfo = new EventInfo(); public readonly List ComboColors = new List { new Color4(17, 136, 170, 255), @@ -40,6 +42,7 @@ namespace osu.Game.Beatmaps { BeatmapInfo = original?.BeatmapInfo ?? BeatmapInfo; TimingInfo = original?.TimingInfo ?? TimingInfo; + EventInfo = original?.EventInfo ?? EventInfo; ComboColors = original?.ComboColors ?? ComboColors; } } diff --git a/osu.Game/Beatmaps/Events/EventType.cs b/osu.Game/Beatmaps/Events/BackgroundEvent.cs similarity index 52% rename from osu.Game/Beatmaps/Events/EventType.cs rename to osu.Game/Beatmaps/Events/BackgroundEvent.cs index 0d4be693f0..215373bd3b 100644 --- a/osu.Game/Beatmaps/Events/EventType.cs +++ b/osu.Game/Beatmaps/Events/BackgroundEvent.cs @@ -3,14 +3,11 @@ namespace osu.Game.Beatmaps.Events { - public enum EventType + public class BackgroundEvent : Event { - Background = 0, - Video = 1, - Break = 2, - Colour = 3, - Sprite = 4, - Sample = 5, - Animation = 6 + /// + /// The file name. + /// + public string Filename; } -} \ No newline at end of file +} diff --git a/osu.Game/Beatmaps/Events/BreakEvent.cs b/osu.Game/Beatmaps/Events/BreakEvent.cs new file mode 100644 index 0000000000..78e33f2fbb --- /dev/null +++ b/osu.Game/Beatmaps/Events/BreakEvent.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Beatmaps.Events +{ + public class BreakEvent : Event + { + /// + /// The minimum duration required for a break to have any effect. + /// + private const double min_break_duration = 650; + + /// + /// The break end time. + /// + public double EndTime; + + /// + /// The duration of the break. + /// + public double Duration => EndTime - StartTime; + + /// + /// Whether the break has any effect. Breaks that are too short are culled before they reach the EventInfo. + /// + public bool HasEffect => Duration >= min_break_duration; + } +} diff --git a/osu.Game/Beatmaps/Events/Event.cs b/osu.Game/Beatmaps/Events/Event.cs new file mode 100644 index 0000000000..3af3909462 --- /dev/null +++ b/osu.Game/Beatmaps/Events/Event.cs @@ -0,0 +1,13 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Beatmaps.Events +{ + public abstract class Event + { + /// + /// The event start time. + /// + public double StartTime; + } +} diff --git a/osu.Game/Beatmaps/Events/EventInfo.cs b/osu.Game/Beatmaps/Events/EventInfo.cs new file mode 100644 index 0000000000..646dea898e --- /dev/null +++ b/osu.Game/Beatmaps/Events/EventInfo.cs @@ -0,0 +1,26 @@ +// 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 System.Linq; + +namespace osu.Game.Beatmaps.Events +{ + public class EventInfo + { + /// + /// All the background events. + /// + public readonly List Backgrounds = new List(); + + /// + /// All the break events. + /// + public readonly List Breaks = new List(); + + /// + /// Total duration of all breaks. + /// + public double TotalBreakTime => Breaks.Sum(b => b.Duration); + } +} diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 95213417ed..772c0e9c07 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -204,23 +204,42 @@ namespace osu.Game.Beatmaps.Formats private void handleEvents(Beatmap beatmap, string val) { - if (val.StartsWith(@"//")) - return; - if (val.StartsWith(@" ")) - return; // TODO string[] split = val.Split(','); + EventType type; - int intType; - if (!int.TryParse(split[0], out intType)) + if (!Enum.TryParse(split[0], out type)) + throw new InvalidDataException($@"Unknown event type {split[0]}"); + + // Todo: Implement the rest + switch (type) { - if (!Enum.TryParse(split[0], out type)) - throw new InvalidDataException($@"Unknown event type {split[0]}"); + case EventType.Video: + case EventType.Background: + string filename = split[2].Trim('"'); + + beatmap.EventInfo.Backgrounds.Add(new BackgroundEvent + { + StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), + Filename = filename + }); + + if (type == EventType.Background) + beatmap.BeatmapInfo.Metadata.BackgroundFile = filename; + + break; + case EventType.Break: + var breakEvent = new BreakEvent + { + StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo), + EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo) + }; + + if (!breakEvent.HasEffect) + return; + + beatmap.EventInfo.Breaks.Add(breakEvent); + break; } - else - type = (EventType)intType; - // TODO: Parse and store the rest of the event - if (type == EventType.Background) - beatmap.BeatmapInfo.Metadata.BackgroundFile = split[2].Trim('"'); } private void handleTimingPoints(Beatmap beatmap, string val) @@ -330,6 +349,9 @@ namespace osu.Game.Beatmaps.Formats if (string.IsNullOrEmpty(line)) continue; + if (line.StartsWith(" ") || line.StartsWith("_") || line.StartsWith("//")) + continue; + if (line.StartsWith(@"osu file format v")) { beatmap.BeatmapInfo.BeatmapVersion = int.Parse(line.Substring(17)); @@ -390,5 +412,16 @@ namespace osu.Game.Beatmaps.Formats Soft = 2, Drum = 3 } + + internal enum EventType + { + Background = 0, + Video = 1, + Break = 2, + Colour = 3, + Sprite = 4, + Sample = 5, + Animation = 6 + } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9352cfba6e..ed2532d238 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -74,6 +74,10 @@ + + + + @@ -342,7 +346,6 @@ - From b52ec11260f4d6a207d63c7232941cc974fddcc7 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Wed, 17 May 2017 20:47:02 +0900 Subject: [PATCH 09/34] Add (almost finished) basis of slider hit object conversion... --- .../Beatmaps/DistanceObjectConversion.cs | 409 ++++++++++++++++++ .../Beatmaps/LegacyConvertType.cs | 62 +++ .../Beatmaps/LegacyConverter.cs | 67 ++- .../Beatmaps/ObjectConversion.cs | 77 ++++ osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs | 44 ++ .../osu.Game.Rulesets.Mania.csproj | 4 + 6 files changed, 657 insertions(+), 6 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs create mode 100644 osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs new file mode 100644 index 0000000000..c775c189e1 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs @@ -0,0 +1,409 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Mania.Objects; +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 OpenTK; +using osu.Game.Database; +using osu.Game.Audio; +using System.Collections.Generic; + +namespace osu.Game.Rulesets.Mania.Beatmaps +{ + internal class DistanceObjectConversion : ObjectConversion + { + private readonly HitObject originalObject; + + private readonly double endTime; + private readonly int repeatCount; + + private LegacyConvertType convertType; + + public DistanceObjectConversion(HitObject originalObject, ObjectRow previousRow, FastRandom random, Beatmap beatmap) + : base(previousRow, random, beatmap) + { + this.originalObject = originalObject; + + ControlPoint overridePoint; + ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(originalObject.StartTime, out overridePoint); + + convertType = LegacyConvertType.None; + if ((overridePoint ?? controlPoint)?.KiaiMode == false) + convertType = LegacyConvertType.LowProbability; + + var distanceData = originalObject as IHasDistance; + var repeatsData = originalObject as IHasRepeats; + + endTime = distanceData?.EndTime ?? 0; + repeatCount = repeatsData?.RepeatCount ?? 1; + } + + public override ObjectRow GenerateConversion() + { + double segmentDuration = endTime / repeatCount; + + if (repeatCount > 1) + { + if (segmentDuration <= 90) + return generateRandomHoldNotes(originalObject.StartTime, endTime, 1); + + if (segmentDuration <= 120) + { + convertType |= LegacyConvertType.ForceNotStack; + return addRandomNotes(originalObject.StartTime, segmentDuration, repeatCount); + } + + if (segmentDuration <= 160) + return addStair(originalObject.StartTime, segmentDuration, repeatCount); + + if (segmentDuration <= 200 && conversionDifficulty > 3) + return addMultipleNotes(originalObject.StartTime, segmentDuration, repeatCount); + + double duration = endTime - originalObject.StartTime; + if (duration >= 4000) + return addNRandomNotes(originalObject.StartTime, endTime, 0.23, 0, 0); + + if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) + return generateTiledHoldNotes(originalObject.StartTime, segmentDuration, repeatCount); + + return generateLongAndNormalNotes(originalObject.StartTime, segmentDuration); + } + + if (segmentDuration <= 110) + { + if (PreviousRow.Columns < AvailableColumns) + convertType |= LegacyConvertType.ForceNotStack; + else + convertType &= ~LegacyConvertType.ForceNotStack; + return addRandomNotes(originalObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); + } + + if (conversionDifficulty > 6.5) + { + if ((convertType & LegacyConvertType.LowProbability) > 0) + return addNRandomNotes(originalObject.StartTime, endTime, 0.78, 0.3, 0); + return addNRandomNotes(originalObject.StartTime, endTime, 0.85, 0.36, 0.03); + } + + if (conversionDifficulty > 4) + { + if ((convertType & LegacyConvertType.LowProbability) > 0) + return addNRandomNotes(originalObject.StartTime, endTime, 0.43, 0.08, 0); + return addNRandomNotes(originalObject.StartTime, endTime, 0.56, 0.18, 0); + } + + if (conversionDifficulty > 2.5) + { + if ((convertType & LegacyConvertType.LowProbability) > 0) + return addNRandomNotes(originalObject.StartTime, endTime, 0.3, 0, 0); + return addNRandomNotes(originalObject.StartTime, endTime, 0.37, 0.08, 0); + } + + if ((convertType & LegacyConvertType.LowProbability) > 0) + return addNRandomNotes(originalObject.StartTime, endTime, 0.17, 0, 0); + return addNRandomNotes(originalObject.StartTime, endTime, 0.27, 0, 0); + } + + /// + /// Adds random hold notes. + /// + /// Number of hold notes. + /// Start time of each hold note. + /// End time of the hold notes. + /// The new row. + private ObjectRow generateRandomHoldNotes(double startTime, double endTime, int count) + { + var newRow = new ObjectRow(); + + int usableColumns = AvailableColumns - RandomStart - PreviousRow.Columns; + int nextColumn = Random.Next(RandomStart, AvailableColumns); + for (int i = 0; i < Math.Min(usableColumns, count); i++) + { + while (newRow.IsTaken(nextColumn) || PreviousRow.IsTaken(nextColumn)) //find available column + nextColumn = Random.Next(RandomStart, AvailableColumns); + add(newRow, nextColumn, startTime, endTime, count); + } + + // This is can't be combined with the above loop due to RNG + for (int i = 0; i < count - usableColumns; i++) + { + while (newRow.IsTaken(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + add(newRow, nextColumn, startTime, endTime, count); + } + + return newRow; + } + + /// + /// Adds random notes, with one note per row. No stacking. + /// + /// The start time. + /// The separation of notes between rows. + /// The number of rows. + /// The new row. + private ObjectRow addRandomNotes(double startTime, double separationTime, int repeatCount) + { + var newRow = new ObjectRow(); + + int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousRow.Columns < AvailableColumns) + { + while (PreviousRow.IsTaken(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + } + + int lastColumn = nextColumn; + for (int i = 0; i <= repeatCount; i++) + { + add(newRow, nextColumn, startTime, startTime); + while (nextColumn == lastColumn) + nextColumn = Random.Next(RandomStart, AvailableColumns); + + lastColumn = nextColumn; + startTime += separationTime; + } + + return newRow; + } + + /// + /// Creates a stair of notes, with one note per row. + /// + /// The start time. + /// The separation of notes between rows. + /// The number of rows/notes. + /// The new row. + private ObjectRow addStair(double startTime, double separationTime, int repeatCount) + { + var newRow = new ObjectRow(); + + int column = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + bool increasing = Random.NextDouble() > 0.5; + + for (int i = 0; i <= repeatCount; i++) + { + add(newRow, column, startTime, startTime); + startTime += separationTime; + + // Check if we're at the borders of the stage, and invert the pattern if so + if (increasing) + { + if (column >= AvailableColumns - 1) + { + increasing = false; + column--; + } + else + column++; + } + else + { + if (column <= RandomStart) + { + increasing = true; + column++; + } + else + column--; + } + } + + return newRow; + } + + /// + /// Adds random notes, with 1-2 notes per row. No stacking. + /// + /// The start time. + /// The separation of notes between rows. + /// The number of rows. + /// The new row. + private ObjectRow addMultipleNotes(double startTime, double separationTime, int repeatCount) + { + var newRow = new ObjectRow(); + + bool legacy = AvailableColumns >= 4 && AvailableColumns <= 8; + int interval = Random.Next(1, AvailableColumns - (legacy ? 1 : 0)); + + int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + for (int i = 0; i <= repeatCount; i++) + { + add(newRow, nextColumn, startTime, startTime, 2); + + nextColumn += interval; + if (nextColumn >= AvailableColumns - RandomStart) + nextColumn = nextColumn - AvailableColumns - RandomStart + (legacy ? 1 : 0); + nextColumn += RandomStart; + + // If we're in 2K, let's not add many consecutive doubles + if (AvailableColumns > 2) + add(newRow, nextColumn, startTime, startTime, 2); + + nextColumn = Random.Next(RandomStart, AvailableColumns); + startTime += separationTime; + } + + return newRow; + } + + /// + /// Generates random hold notes. The amount of hold notes generated is determined by probabilities. + /// + /// The hold note start time. + /// The hold note end time. + /// 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 new row. + private ObjectRow addNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) + { + switch (AvailableColumns) + { + case 2: + p2 = 0; + p3 = 0; + p4 = 0; + break; + case 3: + p2 = Math.Max(p2, 0.1); + p3 = 0; + p4 = 0; + break; + case 4: + p2 = Math.Max(p2, 0.3); + p3 = Math.Max(p3, 0.04); + p4 = 0; + break; + case 5: + p2 = Math.Max(p2, 0.34); + p3 = Math.Max(p3, 0.1); + p4 = Math.Max(p4, 0.03); + break; + } + + 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, originalObject.StartTime - endTime).Any(isDoubleSample); + + if (canGenerateTwoNotes) + p2 = 0; + + return generateRandomHoldNotes(startTime, endTime, GetRandomNoteCount(p2, p3, p4)); + } + + private ObjectRow generateTiledHoldNotes(double startTime, double separationTime, int noteCount) + { + var newRow = new ObjectRow(); + + int columnRepeat = Math.Min(noteCount, AvailableColumns); + + int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousRow.Columns < AvailableColumns) + { + while (PreviousRow.IsTaken(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + } + + for (int i = 0; i < columnRepeat; i++) + { + while (newRow.IsTaken(nextColumn)) + nextColumn = Random.Next(RandomStart, AvailableColumns); + + add(newRow, nextColumn, startTime, endTime, noteCount); + startTime += separationTime; + } + + return newRow; + } + + private ObjectRow generateLongAndNormalNotes(double startTime, double separationTime) + { + var newRow = new ObjectRow(); + + int holdColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); + if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousRow.Columns < AvailableColumns) + { + while (PreviousRow.IsTaken(holdColumn)) + holdColumn = Random.Next(RandomStart, AvailableColumns); + } + + // Create the hold note + add(newRow, holdColumn, startTime, separationTime * repeatCount); + + // Todo: Complete + } + + private void add(ObjectRow row, 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) + + row.Add(newObject); + } + + private SampleInfoList sampleInfoListAt(double time, double separationTime) + { + var curveData = originalObject as IHasCurve; + + if (curveData == null) + return originalObject.Samples; + + int index = (int)(separationTime == 0 ? 0 : (time - originalObject.StartTime) / separationTime); + return curveData.RepeatSamples[index]; + } + + private double? _conversionDifficulty; + private double conversionDifficulty + { + get + { + if (_conversionDifficulty != null) + return _conversionDifficulty.Value; + + HitObject lastObject = Beatmap.HitObjects.LastOrDefault(); + HitObject firstObject = Beatmap.HitObjects.FirstOrDefault(); + + double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0); + drainTime -= Beatmap.EventInfo.TotalBreakTime; + + if (drainTime == 0) + drainTime = 10000; + + BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty; + _conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; + _conversionDifficulty = Math.Min(_conversionDifficulty.Value, 12); + + return _conversionDifficulty.Value; + } + } + } +} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs new file mode 100644 index 0000000000..086bc89292 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConvertType.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Rulesets.Mania.Beatmaps +{ + [Flags] + internal enum LegacyConvertType + { + None = 0, + /// + /// Keep the same as last row. + /// + ForceStack = 1, + /// + /// Keep different from last row. + /// + ForceNotStack = 2, + /// + /// Keep as single note at its original position. + /// + KeepSingle = 4, + /// + /// Use a lower random value. + /// + LowProbability = 8, + /// + /// Reserved. + /// + Alternate = 16, + /// + /// Ignore the repeat count. + /// + ForceSigSlider = 32, + /// + /// Convert slider to circle. + /// + ForceNotSlider = 64, + /// + /// Notes gathered together. + /// + Gathered = 128, + Mirror = 256, + /// + /// Change 0 -> 6. + /// + Reverse = 512, + /// + /// 1 -> 5 -> 1 -> 5 like reverse. + /// + Cycle = 1024, + /// + /// Next note will be at column + 1. + /// + Stair = 2048, + /// + /// Next note will be at column - 1. + /// + ReverseStair = 4096 + } +} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index 544f396f4a..ebc6ed2dcf 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Objects.Types; using System; using System.Collections.Generic; using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Beatmaps.Timing; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -17,28 +18,51 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// internal class LegacyConverter { + private const int max_previous_note_times = 7; + private readonly FastRandom random; + private readonly List previousNoteTimes; + private readonly bool[] previousNotes; + private readonly double lastNoteTime; + private readonly float lastNotePosition; + private readonly int availableColumns; private readonly float localXDivisor; private readonly Beatmap beatmap; - public LegacyConverter(Beatmap beatmap) + public LegacyConverter(ObjectRow previousrow, Beatmap beatmap) { this.beatmap = beatmap; int seed = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.DrainRate + beatmap.BeatmapInfo.Difficulty.CircleSize) * 20 + (int)(beatmap.BeatmapInfo.Difficulty.OverallDifficulty * 41.2) + (int)Math.Round(beatmap.BeatmapInfo.Difficulty.ApproachRate); + random = new FastRandom(seed); availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); localXDivisor = 512.0f / availableColumns; + + previousNoteTimes = new List(max_previous_note_times); + previousNotes = new bool[availableColumns]; } public IEnumerable Convert(HitObject original) { + var maniaOriginal = original as ManiaHitObject; + if (maniaOriginal != null) + { + yield return maniaOriginal; + yield break; + } + if (beatmap.BeatmapInfo.RulesetID == 3) yield return generateSpecific(original); + else + { + foreach (ManiaHitObject c in generateConverted(original)) + yield return c; + } } private ManiaHitObject generateSpecific(HitObject original) @@ -59,12 +83,43 @@ namespace osu.Game.Rulesets.Mania.Beatmaps }; } - return new Note + if (positionData != null) { - StartTime = original.StartTime, - Samples = original.Samples, - Column = column - }; + return new Note + { + StartTime = original.StartTime, + Samples = original.Samples, + Column = column + }; + } + + return null; + } + + private IEnumerable generateConverted(HitObject original) + { + var endTimeData = original as IHasEndTime; + var distanceData = original as IHasDistance; + var positionData = original as IHasPosition; + + ObjectConversion conversion = null; + + if (distanceData != null) + conversion = new DistanceObjectConversion(distanceData, beatmap); + else if (endTimeData != null) + { + // Spinner + } + else if (positionData != null) + { + // Circle + } + + if (conversion == null) + yield break; + + foreach (ManiaHitObject obj in conversion.GenerateConversion()) + yield return obj; } private int getColumn(float position) => MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, availableColumns - 1); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs new file mode 100644 index 0000000000..9dee1116e0 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs @@ -0,0 +1,77 @@ +// 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; + +namespace osu.Game.Rulesets.Mania.Beatmaps +{ + internal abstract class ObjectConversion + { + protected readonly int AvailableColumns; + protected readonly int RandomStart; + + protected ObjectRow PreviousRow; + protected readonly FastRandom Random; + protected readonly Beatmap Beatmap; + + protected ObjectConversion(ObjectRow previousRow, FastRandom random, Beatmap beatmap) + { + PreviousRow = previousRow; + Random = random; + Beatmap = beatmap; + + AvailableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); + RandomStart = AvailableColumns == 8 ? 1 : 0; + } + + /// + /// Generates a new row filled with converted hit objects. + /// + /// The new row. + public abstract ObjectRow GenerateConversion(); + + /// + /// Converts an x-position into a column. + /// + /// The x-position. + /// Whether to treat as 7K + 1. + /// The column. + protected int GetColumn(float position, bool allowSpecial = false) + { + if (allowSpecial && AvailableColumns == 8) + { + const float local_x_divisor = 512f / 7; + return MathHelper.Clamp((int)Math.Floor(position / local_x_divisor), 0, 6) + 1; + } + + float localXDivisor = 512f / AvailableColumns; + return MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, AvailableColumns - 1); + } + + /// + /// Generates a count of notes to be generated from probabilities. + /// + /// Probability for 2 notes to be generated. + /// Probability for 3 notes to be generated. + /// Probability for 4 notes to be generated. + /// Probability for 5 notes to be generated. + /// Probability for 6 notes to be generated. + /// The amount of notes to be generated. + protected int GetRandomNoteCount(double p2, double p3, double p4 = 1, double p5 = 1, double p6 = 1) + { + double val = Random.NextDouble(); + if (val >= 1 - p6) + return 6; + if (val >= 1 - p5) + return 5; + if (val >= 1 - p4) + return 4; + if (val >= 1 - p3) + return 3; + return val >= 1 - p2 ? 2 : 1; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs b/osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs new file mode 100644 index 0000000000..fe51c16bed --- /dev/null +++ b/osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Rulesets.Mania.Objects; +using System.Collections.Generic; +using System.Linq; + +namespace osu.Game.Rulesets.Mania.Beatmaps +{ + internal class ObjectRow + { + private readonly List hitObjects = new List(); + public IEnumerable HitObjects => hitObjects; + + /// + /// Whether a column of this row has been taken. + /// + /// The column index. + /// Whether the column already contains a hit object. + public bool IsTaken(int column) => hitObjects.Exists(h => h.Column == column); + + /// + /// Amount of columns taken up by hit objects in this row. + /// + public int Columns => HitObjects.GroupBy(h => h.Column).Count(); + + /// + /// Adds a hit object to this row. + /// + /// The hit object to add. + public void Add(ManiaHitObject hitObject) => hitObjects.Add(hitObject); + + /// + /// Clears this row. + /// + public void Clear() => hitObjects.Clear(); + + /// + /// Removes a hit object from this row. + /// + /// The hit object to remove. + public bool Remove(ManiaHitObject hitObject) => hitObjects.Remove(hitObject); + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 781dc3e228..36c17ccf04 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,8 +47,12 @@ + + + + From 22128f158cfb774aa284616ed2849f111ccae4c1 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 12:10:01 +0900 Subject: [PATCH 10/34] Fix a few errors. --- osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs | 2 ++ osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs index c775c189e1..5df4279cca 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs @@ -339,6 +339,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps add(newRow, holdColumn, startTime, separationTime * repeatCount); // Todo: Complete + + return newRow; } private void add(ObjectRow row, int column, double startTime, double endTime, int siblings = 1) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index ebc6ed2dcf..7c8e58862b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private readonly Beatmap beatmap; - public LegacyConverter(ObjectRow previousrow, Beatmap beatmap) + public LegacyConverter(Beatmap beatmap) { this.beatmap = beatmap; @@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps if (conversion == null) yield break; - foreach (ManiaHitObject obj in conversion.GenerateConversion()) + foreach (ManiaHitObject obj in conversion.GenerateConversion().HitObjects) yield return obj; } From e9275138e1b0312cdc9e5a306ec52eb86807cad3 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 12:39:37 +0900 Subject: [PATCH 11/34] Finish up DistanceObjectConversion. --- .../Beatmaps/DistanceObjectConversion.cs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs index 5df4279cca..6bc7c8c45c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs @@ -338,7 +338,37 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Create the hold note add(newRow, holdColumn, startTime, separationTime * repeatCount); - // Todo: Complete + int noteCount = 0; + if (conversionDifficulty > 6.5) + noteCount = GetRandomNoteCount(0.63, 0); + else if (conversionDifficulty > 4) + noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0.12 : 0.45, 0); + else if (conversionDifficulty > 2.5) + noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0 : 0.24, 0); + noteCount = Math.Min(AvailableColumns - 1, noteCount); + + bool ignoreHead = !sampleInfoListAt(startTime, separationTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); + int nextColumn = Random.Next(RandomStart, AvailableColumns); + + var tempRow = new ObjectRow(); + for (int i = 0; i <= repeatCount; i++) + { + if (!(ignoreHead && startTime == originalObject.StartTime)) + { + for (int j = 0; j < noteCount; j++) + { + while (tempRow.IsTaken(nextColumn) || nextColumn == holdColumn) + nextColumn = Random.Next(RandomStart, AvailableColumns); + add(tempRow, nextColumn, startTime, startTime, noteCount + 1); + } + } + + foreach (ManiaHitObject obj in tempRow.HitObjects) + newRow.Add(obj); + + tempRow.Clear(); + startTime += separationTime; + } return newRow; } From f6dc85c2f8334d8ab1ab368d4a3d6dcdb6f9c038 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 12:39:51 +0900 Subject: [PATCH 12/34] Fix incorrect note count probabilities. --- osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs index 9dee1116e0..bee7477261 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// Probability for 5 notes to be generated. /// Probability for 6 notes to be generated. /// The amount of notes to be generated. - protected int GetRandomNoteCount(double p2, double p3, double p4 = 1, double p5 = 1, double p6 = 1) + protected int GetRandomNoteCount(double p2, double p3, double p4 = 0, double p5 = 0, double p6 = 0) { double val = Random.NextDouble(); if (val >= 1 - p6) From 16eda2467fc87a563b06f2e6552569968f878063 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 12:50:12 +0900 Subject: [PATCH 13/34] Make compile. --- osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index 7c8e58862b..18dea8ebc3 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -27,6 +27,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private readonly double lastNoteTime; private readonly float lastNotePosition; + private ObjectRow lastRow = new ObjectRow(); + private readonly int availableColumns; private readonly float localXDivisor; @@ -105,7 +107,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps ObjectConversion conversion = null; if (distanceData != null) - conversion = new DistanceObjectConversion(distanceData, beatmap); + conversion = new DistanceObjectConversion(original, lastRow, random, beatmap); else if (endTimeData != null) { // Spinner @@ -118,8 +120,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps if (conversion == null) yield break; - foreach (ManiaHitObject obj in conversion.GenerateConversion().HitObjects) + ObjectRow newRow = conversion.GenerateConversion(); + + foreach (ManiaHitObject obj in newRow.HitObjects) yield return obj; + + lastRow = newRow; } private int getColumn(float position) => MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, availableColumns - 1); From c1a44ea6b4f1d2452ad293d908cf97698b55a2b3 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 13:21:54 +0900 Subject: [PATCH 14/34] Renaming + commenting. --- .../Beatmaps/DistanceObjectConversion.cs | 238 ++++++++++++------ .../Beatmaps/LegacyConverter.cs | 4 +- .../Beatmaps/ObjectConversion.cs | 12 +- .../Beatmaps/{ObjectRow.cs => ObjectList.cs} | 30 ++- .../osu.Game.Rulesets.Mania.csproj | 2 +- 5 files changed, 189 insertions(+), 97 deletions(-) rename osu.Game.Rulesets.Mania/Beatmaps/{ObjectRow.cs => ObjectList.cs} (56%) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs index 6bc7c8c45c..52c5cf16da 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs @@ -12,7 +12,6 @@ using System.Linq; using OpenTK; using osu.Game.Database; using osu.Game.Audio; -using System.Collections.Generic; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -25,8 +24,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private LegacyConvertType convertType; - public DistanceObjectConversion(HitObject originalObject, ObjectRow previousRow, FastRandom random, Beatmap beatmap) - : base(previousRow, random, beatmap) + public DistanceObjectConversion(HitObject originalObject, ObjectList previousObjects, FastRandom random, Beatmap beatmap) + : base(previousObjects, random, beatmap) { this.originalObject = originalObject; @@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps repeatCount = repeatsData?.RepeatCount ?? 1; } - public override ObjectRow GenerateConversion() + public override ObjectList Generate() { double segmentDuration = endTime / repeatCount; @@ -56,113 +55,125 @@ namespace osu.Game.Rulesets.Mania.Beatmaps if (segmentDuration <= 120) { convertType |= LegacyConvertType.ForceNotStack; - return addRandomNotes(originalObject.StartTime, segmentDuration, repeatCount); + return generateRandomNotes(originalObject.StartTime, segmentDuration, repeatCount); } if (segmentDuration <= 160) - return addStair(originalObject.StartTime, segmentDuration, repeatCount); + return generateStair(originalObject.StartTime, segmentDuration, repeatCount); if (segmentDuration <= 200 && conversionDifficulty > 3) - return addMultipleNotes(originalObject.StartTime, segmentDuration, repeatCount); + return generateRandomMultipleNotes(originalObject.StartTime, segmentDuration, repeatCount); double duration = endTime - originalObject.StartTime; if (duration >= 4000) - return addNRandomNotes(originalObject.StartTime, endTime, 0.23, 0, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.23, 0, 0); if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) return generateTiledHoldNotes(originalObject.StartTime, segmentDuration, repeatCount); - return generateLongAndNormalNotes(originalObject.StartTime, segmentDuration); + return generateHoldAndNormalNotes(originalObject.StartTime, segmentDuration); } if (segmentDuration <= 110) { - if (PreviousRow.Columns < AvailableColumns) + if (PreviousObjects.ColumnsFilled < AvailableColumns) convertType |= LegacyConvertType.ForceNotStack; else convertType &= ~LegacyConvertType.ForceNotStack; - return addRandomNotes(originalObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); + return generateRandomNotes(originalObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); } if (conversionDifficulty > 6.5) { if ((convertType & LegacyConvertType.LowProbability) > 0) - return addNRandomNotes(originalObject.StartTime, endTime, 0.78, 0.3, 0); - return addNRandomNotes(originalObject.StartTime, endTime, 0.85, 0.36, 0.03); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.78, 0.3, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.85, 0.36, 0.03); } if (conversionDifficulty > 4) { if ((convertType & LegacyConvertType.LowProbability) > 0) - return addNRandomNotes(originalObject.StartTime, endTime, 0.43, 0.08, 0); - return addNRandomNotes(originalObject.StartTime, endTime, 0.56, 0.18, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.43, 0.08, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.56, 0.18, 0); } if (conversionDifficulty > 2.5) { if ((convertType & LegacyConvertType.LowProbability) > 0) - return addNRandomNotes(originalObject.StartTime, endTime, 0.3, 0, 0); - return addNRandomNotes(originalObject.StartTime, endTime, 0.37, 0.08, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.3, 0, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.37, 0.08, 0); } if ((convertType & LegacyConvertType.LowProbability) > 0) - return addNRandomNotes(originalObject.StartTime, endTime, 0.17, 0, 0); - return addNRandomNotes(originalObject.StartTime, endTime, 0.27, 0, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.17, 0, 0); + return generateNRandomNotes(originalObject.StartTime, endTime, 0.27, 0, 0); } /// - /// Adds random hold notes. + /// Generates random hold notes that start at an span the same amount of rows. /// - /// Number of hold notes. /// Start time of each hold note. /// End time of the hold notes. - /// The new row. - private ObjectRow generateRandomHoldNotes(double startTime, double endTime, int count) + /// Number of hold notes. + /// The containing the hit objects. + private ObjectList generateRandomHoldNotes(double startTime, double endTime, int noteCount) { - var newRow = new ObjectRow(); + // - - - - + // ■ - ■ ■ + // □ - □ □ + // ■ - ■ ■ + + var newObjects = new ObjectList(); + + int usableColumns = AvailableColumns - RandomStart - PreviousObjects.ColumnsFilled; - int usableColumns = AvailableColumns - RandomStart - PreviousRow.Columns; int nextColumn = Random.Next(RandomStart, AvailableColumns); - for (int i = 0; i < Math.Min(usableColumns, count); i++) + for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) { - while (newRow.IsTaken(nextColumn) || PreviousRow.IsTaken(nextColumn)) //find available column + while (newObjects.IsFilled(nextColumn) || PreviousObjects.IsFilled(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); - add(newRow, nextColumn, startTime, endTime, count); + add(newObjects, nextColumn, startTime, endTime, noteCount); } // This is can't be combined with the above loop due to RNG - for (int i = 0; i < count - usableColumns; i++) + for (int i = 0; i < noteCount - usableColumns; i++) { - while (newRow.IsTaken(nextColumn)) + while (newObjects.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - add(newRow, nextColumn, startTime, endTime, count); + add(newObjects, nextColumn, startTime, endTime, noteCount); } - return newRow; + return newObjects; } /// - /// Adds random notes, with one note per row. No stacking. + /// Generates random notes, with one note per row and no stacking. /// /// The start time. /// The separation of notes between rows. /// The number of rows. - /// The new row. - private ObjectRow addRandomNotes(double startTime, double separationTime, int repeatCount) + /// The containing the hit objects. + private ObjectList generateRandomNotes(double startTime, double separationTime, int repeatCount) { - var newRow = new ObjectRow(); + // - - - - + // x - - - + // - - x - + // - - - x + // x - - - + + var newObjects = new ObjectList(); int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousRow.Columns < AvailableColumns) + if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousObjects.ColumnsFilled < AvailableColumns) { - while (PreviousRow.IsTaken(nextColumn)) + while (PreviousObjects.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); } int lastColumn = nextColumn; for (int i = 0; i <= repeatCount; i++) { - add(newRow, nextColumn, startTime, startTime); + add(newObjects, nextColumn, startTime, startTime); while (nextColumn == lastColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); @@ -170,26 +181,35 @@ namespace osu.Game.Rulesets.Mania.Beatmaps startTime += separationTime; } - return newRow; + return newObjects; } /// - /// Creates a stair of notes, with one note per row. + /// Generates a stair of notes, with one note per row. /// /// The start time. /// The separation of notes between rows. /// The number of rows/notes. - /// The new row. - private ObjectRow addStair(double startTime, double separationTime, int repeatCount) + /// The containing the hit objects. + private ObjectList generateStair(double startTime, double separationTime, int repeatCount) { - var newRow = new ObjectRow(); + // - - - - + // x - - - + // - x - - + // - - x - + // - - - x + // - - x - + // - x - - + // x - - - + + var newObjects = new ObjectList(); int column = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); bool increasing = Random.NextDouble() > 0.5; for (int i = 0; i <= repeatCount; i++) { - add(newRow, column, startTime, startTime); + add(newObjects, column, startTime, startTime); startTime += separationTime; // Check if we're at the borders of the stage, and invert the pattern if so @@ -215,19 +235,25 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } } - return newRow; + return newObjects; } /// - /// Adds random notes, with 1-2 notes per row. No stacking. + /// Generates random notes with 1-2 notes per row and no stacking. /// /// The start time. /// The separation of notes between rows. /// The number of rows. - /// The new row. - private ObjectRow addMultipleNotes(double startTime, double separationTime, int repeatCount) + /// The containing the hit objects. + private ObjectList generateRandomMultipleNotes(double startTime, double separationTime, int repeatCount) { - var newRow = new ObjectRow(); + // - - - - + // x - - + // - x x - + // - - - x + // x - x - + + var newObjects = new ObjectList(); bool legacy = AvailableColumns >= 4 && AvailableColumns <= 8; int interval = Random.Next(1, AvailableColumns - (legacy ? 1 : 0)); @@ -235,7 +261,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i <= repeatCount; i++) { - add(newRow, nextColumn, startTime, startTime, 2); + add(newObjects, nextColumn, startTime, startTime, 2); nextColumn += interval; if (nextColumn >= AvailableColumns - RandomStart) @@ -244,13 +270,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // If we're in 2K, let's not add many consecutive doubles if (AvailableColumns > 2) - add(newRow, nextColumn, startTime, startTime, 2); + add(newObjects, nextColumn, startTime, startTime, 2); nextColumn = Random.Next(RandomStart, AvailableColumns); startTime += separationTime; } - return newRow; + return newObjects; } /// @@ -261,9 +287,14 @@ 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 new row. - private ObjectRow addNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) + /// The containing the hit objects. + private ObjectList generateNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) { + // - - - - + // ■ - ■ ■ + // □ - □ □ + // ■ - ■ ■ + switch (AvailableColumns) { case 2: @@ -291,7 +322,7 @@ 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, originalObject.StartTime - endTime).Any(isDoubleSample); + canGenerateTwoNotes &= originalObject.Samples.Any(isDoubleSample) || sampleInfoListAt(originalObject.StartTime).Any(isDoubleSample); if (canGenerateTwoNotes) p2 = 0; @@ -299,44 +330,72 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return generateRandomHoldNotes(startTime, endTime, GetRandomNoteCount(p2, p3, p4)); } - private ObjectRow generateTiledHoldNotes(double startTime, double separationTime, int noteCount) + /// + /// Generates tiled hold notes. You can think of this as a stair of hold notes. + /// + /// 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) { - var newRow = new ObjectRow(); + // - - - - + // ■ ■ ■ ■ + // □ □ □ □ + // □ □ □ □ + // □ □ □ ■ + // □ □ ■ - + // □ ■ - - + // ■ - - - + + var newObjects = new ObjectList(); int columnRepeat = Math.Min(noteCount, AvailableColumns); int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousRow.Columns < AvailableColumns) + if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousObjects.ColumnsFilled < AvailableColumns) { - while (PreviousRow.IsTaken(nextColumn)) + while (PreviousObjects.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); } for (int i = 0; i < columnRepeat; i++) { - while (newRow.IsTaken(nextColumn)) + while (newObjects.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - add(newRow, nextColumn, startTime, endTime, noteCount); + add(newObjects, nextColumn, startTime, endTime, noteCount); startTime += separationTime; } - return newRow; + return newObjects; } - private ObjectRow generateLongAndNormalNotes(double startTime, double separationTime) + /// + /// Generates a hold note alongside normal notes. + /// + /// The start time of notes. + /// The separation time between notes. + /// The containing the hit objects. + private ObjectList generateHoldAndNormalNotes(double startTime, double separationTime) { - var newRow = new ObjectRow(); + // - - - - + // ■ x x - + // ■ - x x + // ■ x - x + // ■ - x x + + var newObjects = new ObjectList(); int holdColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousRow.Columns < AvailableColumns) + if ((convertType & LegacyConvertType.ForceNotStack) > 0 && PreviousObjects.ColumnsFilled < AvailableColumns) { - while (PreviousRow.IsTaken(holdColumn)) + while (PreviousObjects.IsFilled(holdColumn)) holdColumn = Random.Next(RandomStart, AvailableColumns); } // Create the hold note - add(newRow, holdColumn, startTime, separationTime * repeatCount); + add(newObjects, holdColumn, startTime, separationTime * repeatCount); int noteCount = 0; if (conversionDifficulty > 6.5) @@ -347,33 +406,41 @@ namespace osu.Game.Rulesets.Mania.Beatmaps noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0 : 0.24, 0); noteCount = Math.Min(AvailableColumns - 1, noteCount); - bool ignoreHead = !sampleInfoListAt(startTime, separationTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); + 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 tempRow = new ObjectRow(); + var tempObjects = new ObjectList(); for (int i = 0; i <= repeatCount; i++) { if (!(ignoreHead && startTime == originalObject.StartTime)) { for (int j = 0; j < noteCount; j++) { - while (tempRow.IsTaken(nextColumn) || nextColumn == holdColumn) + while (tempObjects.IsFilled(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); - add(tempRow, nextColumn, startTime, startTime, noteCount + 1); + add(tempObjects, nextColumn, startTime, startTime, noteCount + 1); } } - foreach (ManiaHitObject obj in tempRow.HitObjects) - newRow.Add(obj); + foreach (ManiaHitObject obj in tempObjects.HitObjects) + newObjects.Add(obj); - tempRow.Clear(); + tempObjects.Clear(); startTime += separationTime; } - return newRow; + return newObjects; } - private void add(ObjectRow row, int column, double startTime, double endTime, int siblings = 1) + /// + /// Constructs and adds a note to an object list. + /// + /// The list to add to. + /// 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). + private void add(ObjectList objectList, int column, double startTime, double endTime, int siblings = 1) { ManiaHitObject newObject; @@ -399,21 +466,32 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Todo: Consider siblings and write sample volumes (probably at ManiaHitObject level) - row.Add(newObject); + objectList.Add(newObject); } - private SampleInfoList sampleInfoListAt(double time, double separationTime) + /// + /// Retrieves the sample info list at a point in time. + /// + /// The time to retrieve the sample info list from. + /// + /// + private SampleInfoList sampleInfoListAt(double time) { var curveData = originalObject as IHasCurve; if (curveData == null) return originalObject.Samples; - int index = (int)(separationTime == 0 ? 0 : (time - originalObject.StartTime) / separationTime); + double segmentTime = (curveData.EndTime - originalObject.StartTime) / repeatCount; + + int index = (int)(segmentTime == 0 ? 0 : (time - originalObject.StartTime) / segmentTime); return curveData.RepeatSamples[index]; } private double? _conversionDifficulty; + /// + /// A difficulty factor used for various conversion methods from osu!stable. + /// private double conversionDifficulty { get diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index 18dea8ebc3..1acf2fbec2 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private readonly double lastNoteTime; private readonly float lastNotePosition; - private ObjectRow lastRow = new ObjectRow(); + private ObjectList lastRow = new ObjectList(); private readonly int availableColumns; private readonly float localXDivisor; @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps if (conversion == null) yield break; - ObjectRow newRow = conversion.GenerateConversion(); + ObjectList newRow = conversion.Generate(); foreach (ManiaHitObject obj in newRow.HitObjects) yield return obj; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs index bee7477261..42510e8e7b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs @@ -13,13 +13,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps protected readonly int AvailableColumns; protected readonly int RandomStart; - protected ObjectRow PreviousRow; + protected ObjectList PreviousObjects; protected readonly FastRandom Random; protected readonly Beatmap Beatmap; - protected ObjectConversion(ObjectRow previousRow, FastRandom random, Beatmap beatmap) + protected ObjectConversion(ObjectList previousObjects, FastRandom random, Beatmap beatmap) { - PreviousRow = previousRow; + PreviousObjects = previousObjects; Random = random; Beatmap = beatmap; @@ -28,10 +28,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } /// - /// Generates a new row filled with converted hit objects. + /// Generates a new object list filled with converted hit objects. /// - /// The new row. - public abstract ObjectRow GenerateConversion(); + /// The containing the hit objects. + public abstract ObjectList Generate(); /// /// Converts an x-position into a column. diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs b/osu.Game.Rulesets.Mania/Beatmaps/ObjectList.cs similarity index 56% rename from osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs rename to osu.Game.Rulesets.Mania/Beatmaps/ObjectList.cs index fe51c16bed..13bb32a113 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ObjectRow.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ObjectList.cs @@ -1,42 +1,56 @@ // 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; namespace osu.Game.Rulesets.Mania.Beatmaps { - internal class ObjectRow + internal class ObjectList { private readonly List hitObjects = new List(); + + /// + /// All the hit objects contained in this list. + /// public IEnumerable HitObjects => hitObjects; /// - /// Whether a column of this row has been taken. + /// Whether a column of this list has been taken. /// /// The column index. /// Whether the column already contains a hit object. - public bool IsTaken(int column) => hitObjects.Exists(h => h.Column == column); + public bool IsFilled(int column) => hitObjects.Exists(h => h.Column == column); /// - /// Amount of columns taken up by hit objects in this row. + /// Amount of columns taken up by hit objects in this list. /// - public int Columns => HitObjects.GroupBy(h => h.Column).Count(); + public int ColumnsFilled => HitObjects.GroupBy(h => h.Column).Count(); /// - /// Adds a hit object to this row. + /// Adds a hit object to this list. /// /// The hit object to add. public void Add(ManiaHitObject hitObject) => hitObjects.Add(hitObject); /// - /// Clears this row. + /// Copies hit object from another list to this one. + /// + /// The other list. + public void Add(ObjectList other) + { + other.HitObjects.ForEach(Add); + } + + /// + /// Clears this list. /// public void Clear() => hitObjects.Clear(); /// - /// Removes a hit object from this row. + /// Removes a hit object from this list. /// /// The hit object to remove. public bool Remove(ManiaHitObject hitObject) => hitObjects.Remove(hitObject); diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 36c17ccf04..3d93dd3068 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -52,7 +52,7 @@ - + From 7c48fb2b9259c8cc252a4c860aafc9550172d23f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 13:37:22 +0900 Subject: [PATCH 15/34] General fixes. --- .../Beatmaps/DistanceObjectConversion.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs index 52c5cf16da..20ee944dbf 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs @@ -126,7 +126,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var newObjects = new ObjectList(); int usableColumns = AvailableColumns - RandomStart - PreviousObjects.ColumnsFilled; - int nextColumn = Random.Next(RandomStart, AvailableColumns); for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) { @@ -325,7 +324,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps canGenerateTwoNotes &= originalObject.Samples.Any(isDoubleSample) || sampleInfoListAt(originalObject.StartTime).Any(isDoubleSample); if (canGenerateTwoNotes) - p2 = 0; + p2 = 1; return generateRandomHoldNotes(startTime, endTime, GetRandomNoteCount(p2, p3, p4)); } @@ -397,7 +396,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Create the hold note add(newObjects, holdColumn, startTime, separationTime * repeatCount); - int noteCount = 0; + int noteCount = 1; if (conversionDifficulty > 6.5) noteCount = GetRandomNoteCount(0.63, 0); else if (conversionDifficulty > 4) @@ -422,10 +421,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } } - foreach (ManiaHitObject obj in tempObjects.HitObjects) - newObjects.Add(obj); - + newObjects.Add(tempObjects); tempObjects.Clear(); + startTime += separationTime; } From 6010243736f6bd1cc7fc798bd5940c356bcdc36a Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 14:07:57 +0900 Subject: [PATCH 16/34] Fix incorrect uint_to_real factor. --- osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs index 381e24c84c..ff3fd8e4b7 100644 --- a/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs +++ b/osu.Game.Rulesets.Mania/MathUtils/FastRandom.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils /// internal class FastRandom { - private const double uint_to_real = 1.0 / (int.MaxValue + 1.0); + private const double uint_to_real = 1.0 / (uint.MaxValue + 1.0); private const uint int_mask = 0x7FFFFFFF; private const uint y = 842502087; private const uint z = 3579807591; From 6dae5cbacf53281e47506e548442007586e9771f Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 14:08:32 +0900 Subject: [PATCH 17/34] Fix distance object conversion not calculating end time. --- .../Beatmaps/DistanceObjectConversion.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs index 20ee944dbf..0dbc38ded6 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs @@ -17,6 +17,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { internal class DistanceObjectConversion : ObjectConversion { + /// + /// Base osu! slider scoring distance. + /// + private const float osu_base_scoring_distance = 100; + private readonly HitObject originalObject; private readonly double endTime; @@ -39,8 +44,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var distanceData = originalObject as IHasDistance; var repeatsData = originalObject as IHasRepeats; - endTime = distanceData?.EndTime ?? 0; repeatCount = repeatsData?.RepeatCount ?? 1; + + double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(originalObject.StartTime); + double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(originalObject.StartTime) * speedAdjustment; + + // The true distance, accounting for any repeats. This ends up being the drum roll distance later + double distance = distanceData.Distance * repeatCount; + + // The velocity of the osu! hit object - calculated as the velocity of a slider + double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength; + // The duration of the osu! hit object + double osuDuration = distance / osuVelocity; + + endTime = originalObject.StartTime + osuDuration; } public override ObjectList Generate() From de8271ad6bff2193377e12fafbccf0953d99402d Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 14:08:48 +0900 Subject: [PATCH 18/34] Fix out of range exceptions due to out-of-order hitobjects. --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index e9dae95782..37150adb66 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -25,7 +25,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { BeatmapInfo = original.BeatmapInfo, TimingInfo = original.TimingInfo, - HitObjects = original.HitObjects.SelectMany(converter.Convert).ToList() + // We need to sort here, because the converter generates patterns + HitObjects = original.HitObjects.SelectMany(converter.Convert).OrderBy(h => h.StartTime).ToList() }; } From 618c162535162b321f4db36b995f2da873fc8641 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 14:17:23 +0900 Subject: [PATCH 19/34] Move more functions to ObjectConversion + resharper cleanup. --- .../Beatmaps/DistanceObjectConversion.cs | 101 +++--------------- .../Beatmaps/LegacyConverter.cs | 11 -- .../Beatmaps/ObjectConversion.cs | 70 ++++++++++++ 3 files changed, 86 insertions(+), 96 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs index 0dbc38ded6..59d4a7a80c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/DistanceObjectConversion.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 osu.Game.Rulesets.Mania.Objects; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects; @@ -9,8 +8,6 @@ using osu.Game.Rulesets.Objects.Types; using System; using osu.Game.Rulesets.Mania.MathUtils; using System.Linq; -using OpenTK; -using osu.Game.Database; using osu.Game.Audio; namespace osu.Game.Rulesets.Mania.Beatmaps @@ -78,7 +75,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps if (segmentDuration <= 160) return generateStair(originalObject.StartTime, segmentDuration, repeatCount); - if (segmentDuration <= 200 && conversionDifficulty > 3) + if (segmentDuration <= 200 && ConversionDifficulty > 3) return generateRandomMultipleNotes(originalObject.StartTime, segmentDuration, repeatCount); double duration = endTime - originalObject.StartTime; @@ -100,21 +97,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return generateRandomNotes(originalObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); } - if (conversionDifficulty > 6.5) + 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 (conversionDifficulty > 4) + 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 (conversionDifficulty > 2.5) + if (ConversionDifficulty > 2.5) { if ((convertType & LegacyConvertType.LowProbability) > 0) return generateNRandomNotes(originalObject.StartTime, endTime, 0.3, 0, 0); @@ -148,7 +145,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { while (newObjects.IsFilled(nextColumn) || PreviousObjects.IsFilled(nextColumn)) //find available column nextColumn = Random.Next(RandomStart, AvailableColumns); - add(newObjects, nextColumn, startTime, endTime, noteCount); + Add(newObjects, originalObject, nextColumn, startTime, endTime, noteCount); } // This is can't be combined with the above loop due to RNG @@ -156,7 +153,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { while (newObjects.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - add(newObjects, nextColumn, startTime, endTime, noteCount); + Add(newObjects, originalObject, nextColumn, startTime, endTime, noteCount); } return newObjects; @@ -189,7 +186,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps int lastColumn = nextColumn; for (int i = 0; i <= repeatCount; i++) { - add(newObjects, nextColumn, startTime, startTime); + Add(newObjects, originalObject, nextColumn, startTime, startTime); while (nextColumn == lastColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); @@ -225,7 +222,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps for (int i = 0; i <= repeatCount; i++) { - add(newObjects, column, startTime, startTime); + Add(newObjects, originalObject, column, startTime, startTime); startTime += separationTime; // Check if we're at the borders of the stage, and invert the pattern if so @@ -277,7 +274,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps int nextColumn = GetColumn((originalObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i <= repeatCount; i++) { - add(newObjects, nextColumn, startTime, startTime, 2); + Add(newObjects, originalObject, nextColumn, startTime, startTime, 2); nextColumn += interval; if (nextColumn >= AvailableColumns - RandomStart) @@ -286,7 +283,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // If we're in 2K, let's not add many consecutive doubles if (AvailableColumns > 2) - add(newObjects, nextColumn, startTime, startTime, 2); + Add(newObjects, originalObject, nextColumn, startTime, startTime, 2); nextColumn = Random.Next(RandomStart, AvailableColumns); startTime += separationTime; @@ -380,7 +377,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps while (newObjects.IsFilled(nextColumn)) nextColumn = Random.Next(RandomStart, AvailableColumns); - add(newObjects, nextColumn, startTime, endTime, noteCount); + Add(newObjects, originalObject, nextColumn, startTime, endTime, noteCount); startTime += separationTime; } @@ -411,14 +408,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } // Create the hold note - add(newObjects, holdColumn, startTime, separationTime * repeatCount); + Add(newObjects, originalObject, holdColumn, startTime, separationTime * repeatCount); int noteCount = 1; - if (conversionDifficulty > 6.5) + if (ConversionDifficulty > 6.5) noteCount = GetRandomNoteCount(0.63, 0); - else if (conversionDifficulty > 4) + else if (ConversionDifficulty > 4) noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0.12 : 0.45, 0); - else if (conversionDifficulty > 2.5) + else if (ConversionDifficulty > 2.5) noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0 : 0.24, 0); noteCount = Math.Min(AvailableColumns - 1, noteCount); @@ -434,7 +431,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { while (tempObjects.IsFilled(nextColumn) || nextColumn == holdColumn) nextColumn = Random.Next(RandomStart, AvailableColumns); - add(tempObjects, nextColumn, startTime, startTime, noteCount + 1); + Add(tempObjects, originalObject, nextColumn, startTime, startTime, noteCount + 1); } } @@ -447,48 +444,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return newObjects; } - /// - /// Constructs and adds a note to an object list. - /// - /// The list to add to. - /// 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). - private void add(ObjectList objectList, 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); - } - /// /// Retrieves the sample info list at a point in time. /// /// The time to retrieve the sample info list from. - /// /// private SampleInfoList sampleInfoListAt(double time) { @@ -502,33 +461,5 @@ namespace osu.Game.Rulesets.Mania.Beatmaps int index = (int)(segmentTime == 0 ? 0 : (time - originalObject.StartTime) / segmentTime); return curveData.RepeatSamples[index]; } - - private double? _conversionDifficulty; - /// - /// A difficulty factor used for various conversion methods from osu!stable. - /// - private double conversionDifficulty - { - get - { - if (_conversionDifficulty != null) - return _conversionDifficulty.Value; - - HitObject lastObject = Beatmap.HitObjects.LastOrDefault(); - HitObject firstObject = Beatmap.HitObjects.FirstOrDefault(); - - double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0); - drainTime -= Beatmap.EventInfo.TotalBreakTime; - - if (drainTime == 0) - drainTime = 10000; - - BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty; - _conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; - _conversionDifficulty = Math.Min(_conversionDifficulty.Value, 12); - - return _conversionDifficulty.Value; - } - } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs index 1acf2fbec2..0a85b8c8af 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyConverter.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Objects.Types; using System; using System.Collections.Generic; using osu.Game.Rulesets.Mania.MathUtils; -using osu.Game.Beatmaps.Timing; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -18,15 +17,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// internal class LegacyConverter { - private const int max_previous_note_times = 7; - private readonly FastRandom random; - private readonly List previousNoteTimes; - private readonly bool[] previousNotes; - private readonly double lastNoteTime; - private readonly float lastNotePosition; - private ObjectList lastRow = new ObjectList(); private readonly int availableColumns; @@ -44,9 +36,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); localXDivisor = 512.0f / availableColumns; - - previousNoteTimes = new List(max_previous_note_times); - previousNotes = new bool[availableColumns]; } public IEnumerable Convert(HitObject original) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs index 42510e8e7b..83c0af9d46 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ObjectConversion.cs @@ -5,6 +5,10 @@ using OpenTK; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.MathUtils; using System; +using System.Linq; +using osu.Game.Database; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -73,5 +77,71 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return 3; 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. + /// + protected double ConversionDifficulty + { + get + { + if (conversionDifficulty != null) + return conversionDifficulty.Value; + + HitObject lastObject = Beatmap.HitObjects.LastOrDefault(); + HitObject firstObject = Beatmap.HitObjects.FirstOrDefault(); + + double drainTime = (lastObject?.StartTime ?? 0) - (firstObject?.StartTime ?? 0); + drainTime -= Beatmap.EventInfo.TotalBreakTime; + + if (drainTime == 0) + drainTime = 10000; + + BeatmapDifficulty difficulty = Beatmap.BeatmapInfo.Difficulty; + conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + Beatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; + conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); + + return conversionDifficulty.Value; + } + } } } From 1fa1897d71122d08ad93e8a82be35af6a87d0485 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 15:05:45 +0900 Subject: [PATCH 20/34] 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 @@ - - - - + + + + + - + From 164a1bb743f9c8bbf7ec2998199a0b431259fa9b Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 15:35:16 +0900 Subject: [PATCH 21/34] Remove distance object pattern generator for now (next PR). --- .../Beatmaps/LegacyBeatmapConverter.cs | 16 +- .../Legacy/DistanceObjectPatternGenerator.cs | 463 ------------------ .../osu.Game.Rulesets.Mania.csproj | 1 - 3 files changed, 3 insertions(+), 477 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index 4108ba7809..4a98751b9d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -4,8 +4,6 @@ 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; @@ -18,10 +16,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// internal class LegacyBeatmapConverter { - private readonly FastRandom random; - - private Patterns.Pattern lastPattern = new Patterns.Pattern(); - private readonly int availableColumns; private readonly float localXDivisor; @@ -31,10 +25,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { this.beatmap = beatmap; - int seed = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.DrainRate + beatmap.BeatmapInfo.Difficulty.CircleSize) - * 20 + (int)(beatmap.BeatmapInfo.Difficulty.OverallDifficulty * 41.2) + (int)Math.Round(beatmap.BeatmapInfo.Difficulty.ApproachRate); - random = new FastRandom(seed); - availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); localXDivisor = 512.0f / availableColumns; } @@ -97,7 +87,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps Patterns.PatternGenerator conversion = null; if (distanceData != null) - conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern); + { + // Slider + } else if (endTimeData != null) { // Spinner @@ -114,8 +106,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps foreach (ManiaHitObject obj in newPattern.HitObjects) yield return obj; - - 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/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs deleted file mode 100644 index 03240a2be4..0000000000 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ /dev/null @@ -1,463 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -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.Patterns.Legacy -{ - /// - /// 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 double endTime; - private readonly int repeatCount; - - private PatternType convertType; - - public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) - : base(random, hitObject, beatmap, previousPattern) - { - ControlPoint overridePoint; - ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint); - - convertType = PatternType.None; - if ((overridePoint ?? controlPoint)?.KiaiMode == false) - convertType = PatternType.LowProbability; - - var distanceData = hitObject as IHasDistance; - var repeatsData = hitObject as IHasRepeats; - - repeatCount = repeatsData?.RepeatCount ?? 1; - - 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; - - // The velocity of the osu! hit object - calculated as the velocity of a slider - double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength; - // The duration of the osu! hit object - double osuDuration = distance / osuVelocity; - - endTime = hitObject.StartTime + osuDuration; - } - - public override Pattern Generate() - { - double segmentDuration = endTime / repeatCount; - - if (repeatCount > 1) - { - if (segmentDuration <= 90) - return generateRandomHoldNotes(HitObject.StartTime, endTime, 1); - - if (segmentDuration <= 120) - { - convertType |= PatternType.ForceNotStack; - return generateRandomNotes(HitObject.StartTime, segmentDuration, repeatCount); - } - - if (segmentDuration <= 160) - return generateStair(HitObject.StartTime, segmentDuration); - - if (segmentDuration <= 200 && ConversionDifficulty > 3) - return generateRandomMultipleNotes(HitObject.StartTime, segmentDuration, repeatCount); - - double duration = endTime - HitObject.StartTime; - if (duration >= 4000) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.23, 0, 0); - - if (segmentDuration > 400 && duration < 4000 && repeatCount < AvailableColumns - 1 - RandomStart) - return generateTiledHoldNotes(HitObject.StartTime, segmentDuration, repeatCount); - - return generateHoldAndNormalNotes(HitObject.StartTime, segmentDuration); - } - - if (segmentDuration <= 110) - { - if (PreviousPattern.ColumnsFilled < AvailableColumns) - convertType |= PatternType.ForceNotStack; - else - convertType &= ~PatternType.ForceNotStack; - return generateRandomNotes(HitObject.StartTime, segmentDuration, segmentDuration < 80 ? 0 : 1); - } - - if (ConversionDifficulty > 6.5) - { - 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 & 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 & PatternType.LowProbability) > 0) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.3, 0, 0); - return generateNRandomNotes(HitObject.StartTime, endTime, 0.37, 0.08, 0); - } - - if ((convertType & PatternType.LowProbability) > 0) - return generateNRandomNotes(HitObject.StartTime, endTime, 0.17, 0, 0); - return generateNRandomNotes(HitObject.StartTime, endTime, 0.27, 0, 0); - } - - /// - /// Generates random hold notes that start at an span the same amount of rows. - /// - /// Start time of each hold note. - /// End time of the hold notes. - /// Number of hold notes. - /// The containing the hit objects. - private Pattern generateRandomHoldNotes(double startTime, double endTime, int noteCount) - { - // - - - - - // ■ - ■ ■ - // □ - □ □ - // ■ - ■ ■ - - var pattern = new Pattern(); - - int usableColumns = AvailableColumns - RandomStart - PreviousPattern.ColumnsFilled; - int nextColumn = Random.Next(RandomStart, AvailableColumns); - for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) - { - while (pattern.IsFilled(nextColumn) || PreviousPattern.IsFilled(nextColumn)) //find available column - nextColumn = Random.Next(RandomStart, AvailableColumns); - 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 (pattern.IsFilled(nextColumn)) - nextColumn = Random.Next(RandomStart, AvailableColumns); - AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); - } - - return pattern; - } - - /// - /// Generates random notes, with one note per row and no stacking. - /// - /// The start time. - /// The separation of notes between rows. - /// The number of rows. - /// The containing the hit objects. - private Pattern generateRandomNotes(double startTime, double separationTime, int repeatCount) - { - // - - - - - // x - - - - // - - x - - // - - - x - // x - - - - - var pattern = new Pattern(); - - int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) - { - while (PreviousPattern.IsFilled(nextColumn)) - nextColumn = Random.Next(RandomStart, AvailableColumns); - } - - int lastColumn = nextColumn; - for (int i = 0; i <= repeatCount; i++) - { - AddToPattern(pattern, HitObject, nextColumn, startTime, startTime); - while (nextColumn == lastColumn) - nextColumn = Random.Next(RandomStart, AvailableColumns); - - lastColumn = nextColumn; - startTime += separationTime; - } - - return pattern; - } - - /// - /// Generates a stair of notes, with one note per row. - /// - /// The start time. - /// The separation of notes between rows. - /// The containing the hit objects. - private Pattern generateStair(double startTime, double separationTime) - { - // - - - - - // x - - - - // - x - - - // - - x - - // - - - x - // - - x - - // - x - - - // x - - - - - var pattern = new Pattern(); - - int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - bool increasing = Random.NextDouble() > 0.5; - - for (int i = 0; i <= repeatCount; i++) - { - AddToPattern(pattern, HitObject, column, startTime, startTime); - startTime += separationTime; - - // Check if we're at the borders of the stage, and invert the pattern if so - if (increasing) - { - if (column >= AvailableColumns - 1) - { - increasing = false; - column--; - } - else - column++; - } - else - { - if (column <= RandomStart) - { - increasing = true; - column++; - } - else - column--; - } - } - - return pattern; - } - - /// - /// Generates random notes with 1-2 notes per row and no stacking. - /// - /// The start time. - /// The separation of notes between rows. - /// The number of rows. - /// The containing the hit objects. - private Pattern generateRandomMultipleNotes(double startTime, double separationTime, int repeatCount) - { - // - - - - - // x - - - // - x x - - // - - - x - // x - x - - - var pattern = new Pattern(); - - bool legacy = AvailableColumns >= 4 && AvailableColumns <= 8; - int interval = Random.Next(1, AvailableColumns - (legacy ? 1 : 0)); - - int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - for (int i = 0; i <= repeatCount; i++) - { - AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); - - nextColumn += interval; - if (nextColumn >= AvailableColumns - RandomStart) - nextColumn = nextColumn - AvailableColumns - RandomStart + (legacy ? 1 : 0); - nextColumn += RandomStart; - - // If we're in 2K, let's not add many consecutive doubles - if (AvailableColumns > 2) - AddToPattern(pattern, HitObject, nextColumn, startTime, startTime, 2); - - nextColumn = Random.Next(RandomStart, AvailableColumns); - startTime += separationTime; - } - - return pattern; - } - - /// - /// Generates random hold notes. The amount of hold notes generated is determined by probabilities. - /// - /// The hold note start time. - /// The hold note end time. - /// 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 Pattern generateNRandomNotes(double startTime, double endTime, double p2, double p3, double p4) - { - // - - - - - // ■ - ■ ■ - // □ - □ □ - // ■ - ■ ■ - - switch (AvailableColumns) - { - case 2: - p2 = 0; - p3 = 0; - p4 = 0; - break; - case 3: - p2 = Math.Max(p2, 0.1); - p3 = 0; - p4 = 0; - break; - case 4: - p2 = Math.Max(p2, 0.3); - p3 = Math.Max(p3, 0.04); - p4 = 0; - break; - case 5: - p2 = Math.Max(p2, 0.34); - p3 = Math.Max(p3, 0.1); - p4 = Math.Max(p4, 0.03); - break; - } - - Func isDoubleSample = sample => sample.Name == SampleInfo.HIT_CLAP && sample.Name == SampleInfo.HIT_FINISH; - - bool canGenerateTwoNotes = (convertType & PatternType.LowProbability) == 0; - canGenerateTwoNotes &= HitObject.Samples.Any(isDoubleSample) || sampleInfoListAt(HitObject.StartTime).Any(isDoubleSample); - - if (canGenerateTwoNotes) - p2 = 1; - - return generateRandomHoldNotes(startTime, endTime, GetRandomNoteCount(p2, p3, p4)); - } - - /// - /// Generates tiled hold notes. You can think of this as a stair of hold notes. - /// - /// The first hold note start time. - /// The separation time between hold notes. - /// The amount of hold notes. - /// The containing the hit objects. - private Pattern generateTiledHoldNotes(double startTime, double separationTime, int noteCount) - { - // - - - - - // ■ ■ ■ ■ - // □ □ □ □ - // □ □ □ □ - // □ □ □ ■ - // □ □ ■ - - // □ ■ - - - // ■ - - - - - var pattern = new Pattern(); - - int columnRepeat = Math.Min(noteCount, AvailableColumns); - - int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) - { - while (PreviousPattern.IsFilled(nextColumn)) - nextColumn = Random.Next(RandomStart, AvailableColumns); - } - - for (int i = 0; i < columnRepeat; i++) - { - while (pattern.IsFilled(nextColumn)) - nextColumn = Random.Next(RandomStart, AvailableColumns); - - AddToPattern(pattern, HitObject, nextColumn, startTime, endTime, noteCount); - startTime += separationTime; - } - - return pattern; - } - - /// - /// Generates a hold note alongside normal notes. - /// - /// The start time of notes. - /// The separation time between notes. - /// The containing the hit objects. - private Pattern generateHoldAndNormalNotes(double startTime, double separationTime) - { - // - - - - - // ■ x x - - // ■ - x x - // ■ x - x - // ■ - x x - - var pattern = new Pattern(); - - int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); - if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnsFilled < AvailableColumns) - { - while (PreviousPattern.IsFilled(holdColumn)) - holdColumn = Random.Next(RandomStart, AvailableColumns); - } - - // Create the hold note - AddToPattern(pattern, HitObject, holdColumn, startTime, separationTime * repeatCount); - - int noteCount = 1; - if (ConversionDifficulty > 6.5) - noteCount = GetRandomNoteCount(0.63, 0); - else if (ConversionDifficulty > 4) - noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0.12 : 0.45, 0); - else if (ConversionDifficulty > 2.5) - noteCount = GetRandomNoteCount(AvailableColumns < 6 ? 0 : 0.24, 0); - noteCount = Math.Min(AvailableColumns - 1, noteCount); - - 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 rowPattern = new Pattern(); - for (int i = 0; i <= repeatCount; i++) - { - if (!(ignoreHead && startTime == HitObject.StartTime)) - { - for (int j = 0; j < noteCount; j++) - { - while (rowPattern.IsFilled(nextColumn) || nextColumn == holdColumn) - nextColumn = Random.Next(RandomStart, AvailableColumns); - AddToPattern(rowPattern, HitObject, nextColumn, startTime, startTime, noteCount + 1); - } - } - - pattern.Add(rowPattern); - rowPattern.Clear(); - - startTime += separationTime; - } - - return pattern; - } - - /// - /// Retrieves the sample info list at a point in time. - /// - /// The time to retrieve the sample info list from. - /// - private SampleInfoList sampleInfoListAt(double time) - { - var curveData = HitObject as IHasCurve; - - if (curveData == null) - return HitObject.Samples; - - double segmentTime = (curveData.EndTime - HitObject.StartTime) / repeatCount; - - int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime); - return curveData.RepeatSamples[index]; - } - } -} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 9de9cd703f..ea65588a81 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -47,7 +47,6 @@ - From af34777f44b93c4c23e2214dd352f2b6647ed8d6 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 17:00:11 +0900 Subject: [PATCH 22/34] Trim whitespace. --- osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs | 2 +- osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index 4a98751b9d..ceb83be7ca 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps internal class LegacyBeatmapConverter { private readonly int availableColumns; - private readonly float localXDivisor; + private readonly float localXDivisor; private readonly Beatmap beatmap; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs index 81aeb48c01..6ccd39c6ac 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns /// The hit object to create the pattern for. /// protected readonly HitObject HitObject; - + /// /// The beatmap which is a part of. /// From 873ff344874d16bcf7494450ba0a7b13e5b9022c Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 17:43:59 +0900 Subject: [PATCH 23/34] This function can't be used for all pattern generations. So let's not use it. --- .../Beatmaps/Patterns/PatternGenerator.cs | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs index 6ccd39c6ac..558d64080b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs @@ -47,43 +47,5 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns /// /// 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); - } } } From afd3eb4b8d53e020d1b971c4cd76d234fd0c683a Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:04:32 +0900 Subject: [PATCH 24/34] Implement things a bit more to remove warnings. --- .../Beatmaps/LegacyBeatmapConverter.cs | 113 +++++++++++------- .../Beatmaps/Patterns/PatternGenerator.cs | 1 - osu.Game/Beatmaps/Events/EventInfo.cs | 7 ++ 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index ceb83be7ca..3aa88af62d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -7,7 +7,8 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; -using OpenTK; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns; +using osu.Game.Rulesets.Mania.MathUtils; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -16,17 +17,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// internal class LegacyBeatmapConverter { - private readonly int availableColumns; - private readonly float localXDivisor; + private Pattern lastPattern = new Pattern(); + private readonly FastRandom random; private readonly Beatmap beatmap; public LegacyBeatmapConverter(Beatmap beatmap) { this.beatmap = beatmap; - availableColumns = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.CircleSize); - localXDivisor = 512.0f / availableColumns; + int seed = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.DrainRate + beatmap.BeatmapInfo.Difficulty.CircleSize) + * 20 + (int)(beatmap.BeatmapInfo.Difficulty.OverallDifficulty * 41.2) + (int)Math.Round(beatmap.BeatmapInfo.Difficulty.ApproachRate); + random = new FastRandom(seed); } public IEnumerable Convert(HitObject original) @@ -38,44 +40,32 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield break; } - if (beatmap.BeatmapInfo.RulesetID == 3) - yield return generateSpecific(original); - else + IEnumerable objects = null; + switch (beatmap.BeatmapInfo.RulesetID) { - foreach (ManiaHitObject c in generateConverted(original)) - yield return c; + default: + objects = generateConverted(original); + break; + case 3: + objects = generateSpecific(original); + break; } + + if (objects == null) + yield break; + + foreach (ManiaHitObject obj in objects) + yield return obj; } - private ManiaHitObject generateSpecific(HitObject original) + private IEnumerable generateSpecific(HitObject original) { - var endTimeData = original as IHasEndTime; - var positionData = original as IHasXPosition; + var generator = new SpecificPatternGenerator(random, original, beatmap, lastPattern); - int column = getColumn(positionData?.X ?? 0); + Pattern newPattern = generator.Generate(); + lastPattern = newPattern; - if (endTimeData != null) - { - return new HoldNote - { - StartTime = original.StartTime, - Samples = original.Samples, - Duration = endTimeData.Duration, - Column = column, - }; - } - - if (positionData != null) - { - return new Note - { - StartTime = original.StartTime, - Samples = original.Samples, - Column = column - }; - } - - return null; + return newPattern.HitObjects; } private IEnumerable generateConverted(HitObject original) @@ -84,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var distanceData = original as IHasDistance; var positionData = original as IHasPosition; - Patterns.PatternGenerator conversion = null; + PatternGenerator conversion = null; if (distanceData != null) { @@ -100,14 +90,53 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } if (conversion == null) - yield break; + return new ManiaHitObject[0]; - Patterns.Pattern newPattern = conversion.Generate(); + Pattern newPattern = conversion.Generate(); + lastPattern = newPattern; - foreach (ManiaHitObject obj in newPattern.HitObjects) - yield return obj; + return newPattern.HitObjects; } - private int getColumn(float position) => MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, availableColumns - 1); + /// + /// A pattern generator for mania-specific beatmaps. + /// + private class SpecificPatternGenerator : Patterns.Legacy.PatternGenerator + { + public SpecificPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(random, hitObject, beatmap, previousPattern) + { + } + + public override Pattern Generate() + { + var endTimeData = HitObject as IHasEndTime; + var positionData = HitObject as IHasXPosition; + + var pattern = new Pattern(); + + if (endTimeData != null) + { + pattern.Add(new HoldNote + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Duration = endTimeData.Duration, + Column = GetColumn(positionData?.X ?? 0), + }); + } + else if (positionData != null) + { + pattern.Add(new Note + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Column = GetColumn(positionData?.X ?? 0) + }); + } + + return pattern; + } + } } } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs index 558d64080b..dda4d07182 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs @@ -3,7 +3,6 @@ using System; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns diff --git a/osu.Game/Beatmaps/Events/EventInfo.cs b/osu.Game/Beatmaps/Events/EventInfo.cs index 646dea898e..3ba3d5ba03 100644 --- a/osu.Game/Beatmaps/Events/EventInfo.cs +++ b/osu.Game/Beatmaps/Events/EventInfo.cs @@ -22,5 +22,12 @@ namespace osu.Game.Beatmaps.Events /// Total duration of all breaks. /// public double TotalBreakTime => Breaks.Sum(b => b.Duration); + + /// + /// Retrieves the active background at a time. + /// + /// The time to retrieve the background at. + /// The background. + public BackgroundEvent BackgroundAt(double time) => Backgrounds.FirstOrDefault(b => b.StartTime <= time); } } From af129b3eaba1233654e87b6de4185876933ba033 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:13:08 +0900 Subject: [PATCH 25/34] Add siblings, will be used in generator branches. --- osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs index 93aaa94f45..f6eb4aea2c 100644 --- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObject.cs @@ -9,5 +9,11 @@ namespace osu.Game.Rulesets.Mania.Objects public abstract class ManiaHitObject : HitObject, IHasColumn { public int Column { get; set; } + + /// + /// The number of other that start at + /// the same time as this hit object. + /// + public int Siblings { get; set; } } } From c80e2e8f0a16840448874d861790db4ba59c765c Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 18:46:50 +0900 Subject: [PATCH 26/34] Attempt to solve warnings... --- .../Beatmaps/LegacyBeatmapConverter.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs index 3aa88af62d..e3045df185 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield break; } - IEnumerable objects = null; + IEnumerable objects; switch (beatmap.BeatmapInfo.RulesetID) { default: @@ -74,7 +74,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var distanceData = original as IHasDistance; var positionData = original as IHasPosition; - PatternGenerator conversion = null; + // Following lines currently commented out to appease resharper + + //PatternGenerator conversion = null; if (distanceData != null) { @@ -89,13 +91,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps // Circle } - if (conversion == null) - return new ManiaHitObject[0]; + //if (conversion == null) + return null; - Pattern newPattern = conversion.Generate(); - lastPattern = newPattern; + //Pattern newPattern = conversion.Generate(); + //lastPattern = newPattern; - return newPattern.HitObjects; + //return newPattern.HitObjects; } /// @@ -113,6 +115,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps var endTimeData = HitObject as IHasEndTime; var positionData = HitObject as IHasXPosition; + int column = GetColumn(positionData?.X ?? 0); + var pattern = new Pattern(); if (endTimeData != null) @@ -122,7 +126,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps StartTime = HitObject.StartTime, Samples = HitObject.Samples, Duration = endTimeData.Duration, - Column = GetColumn(positionData?.X ?? 0), + Column = column, }); } else if (positionData != null) @@ -131,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { StartTime = HitObject.StartTime, Samples = HitObject.Samples, - Column = GetColumn(positionData?.X ?? 0) + Column = column }); } From 4e8ead9cf450e47713e39b16cf2050e59254cbe4 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Thu, 18 May 2017 19:05:03 +0900 Subject: [PATCH 27/34] Fix possible nullref. --- osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index 3c31c6b854..b699758c3e 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.UI return t; }); - double lastObjectTime = (Objects.Last() as IHasEndTime)?.EndTime ?? Objects.Last().StartTime; + double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; // Perform some post processing of the timing changes timingChanges = timingChanges From 67cf64062ae46bf1ce5104ba2f0267829613953d Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 15:57:32 +0900 Subject: [PATCH 28/34] Add flag to determine whether the beatmap requested for conversion is for the current ruleset. --- .../Tests/TestCaseGamefield.cs | 8 ++++---- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- .../UI/CatchHitRenderer.cs | 4 ++-- .../Beatmaps/ManiaBeatmapConverter.cs | 12 ++++++++++- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../UI/ManiaHitRenderer.cs | 4 ++-- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs | 4 ++-- .../Beatmaps/TaikoBeatmapConverter.cs | 4 ++-- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- .../UI/TaikoHitRenderer.cs | 4 ++-- osu.Game/Beatmaps/DifficultyCalculator.cs | 2 +- .../Rulesets/Beatmaps/BeatmapConverter.cs | 8 +++++--- osu.Game/Rulesets/Ruleset.cs | 7 ++++--- osu.Game/Rulesets/UI/HitRenderer.cs | 20 ++++++++++++++----- osu.Game/Screens/Play/Player.cs | 4 ++-- 16 files changed, 56 insertions(+), 33 deletions(-) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs index 1049a8818a..6bd9d35b80 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseGamefield.cs @@ -85,25 +85,25 @@ namespace osu.Desktop.VisualTests.Tests Clock = new FramedClock(), Children = new Drawable[] { - new OsuHitRenderer(beatmap) + new OsuHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft }, - new TaikoHitRenderer(beatmap) + new TaikoHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.TopRight, Origin = Anchor.TopRight }, - new CatchHitRenderer(beatmap) + new CatchHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft }, - new ManiaHitRenderer(beatmap) + new ManiaHitRenderer(beatmap, false) { Scale = new Vector2(0.5f), Anchor = Anchor.BottomRight, diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index a6faf13d51..53449fd5f5 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch { public class CatchRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new CatchHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetModsFor(ModType type) { diff --git a/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs b/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs index f34585be55..179440adb3 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchHitRenderer.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchHitRenderer : HitRenderer { - public CatchHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public CatchHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index aea77cd2b5..9740c3279d 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -16,8 +16,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; - protected override Beatmap ConvertBeatmap(Beatmap original) + protected override Beatmap ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) { + // Todo: This should be cased when we get better conversion methods var converter = new LegacyBeatmapConverter(original); @@ -32,6 +33,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { + var maniaOriginal = original as ManiaHitObject; + if (maniaOriginal != null) + { + yield return maniaOriginal; + yield break; + } + + + // Handled by the LegacyConvereter yield return null; } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 26614075b1..30d1846746 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania { public class ManiaRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new ManiaHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new ManiaHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetModsFor(ModType type) { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs index b699758c3e..0bf70017e3 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaHitRenderer.cs @@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Mania.UI { public int? Columns; - public ManiaHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public ManiaHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 39e911651a..af4a099e0d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu { public class OsuRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new OsuHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new OsuHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] { diff --git a/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs b/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs index 687518e6d5..e582d2fcd3 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuHitRenderer.cs @@ -18,8 +18,8 @@ namespace osu.Game.Rulesets.Osu.UI { public class OsuHitRenderer : HitRenderer { - public OsuHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public OsuHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 355ce1cf68..a2dea3731e 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -41,13 +41,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(HitObject) }; - protected override Beatmap ConvertBeatmap(Beatmap original) + protected override Beatmap ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) { // Rewrite the beatmap info to add the slider velocity multiplier BeatmapInfo info = original.BeatmapInfo.DeepClone(); info.Difficulty.SliderMultiplier *= legacy_velocity_multiplier; - Beatmap converted = base.ConvertBeatmap(original); + Beatmap converted = base.ConvertBeatmap(original, isForCurrentRuleset); // Post processing step to transform hit objects with the same start time into strong hits converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x => diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 3fb2cf6c28..7c169f820b 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko { public class TaikoRuleset : Ruleset { - public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap) => new TaikoHitRenderer(beatmap); + public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new TaikoHitRenderer(beatmap, isForCurrentRuleset); public override IEnumerable GetModsFor(ModType type) { diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoHitRenderer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoHitRenderer.cs index db15193ce5..73450d576d 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoHitRenderer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoHitRenderer.cs @@ -22,8 +22,8 @@ namespace osu.Game.Rulesets.Taiko.UI { public class TaikoHitRenderer : HitRenderer { - public TaikoHitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + public TaikoHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { } diff --git a/osu.Game/Beatmaps/DifficultyCalculator.cs b/osu.Game/Beatmaps/DifficultyCalculator.cs index 8e9266b644..f483d1e6e3 100644 --- a/osu.Game/Beatmaps/DifficultyCalculator.cs +++ b/osu.Game/Beatmaps/DifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps protected DifficultyCalculator(Beatmap beatmap) { - Objects = CreateBeatmapConverter().Convert(beatmap).HitObjects; + Objects = CreateBeatmapConverter().Convert(beatmap, true).HitObjects; foreach (var h in Objects) h.ApplyDefaults(beatmap.TimingInfo, beatmap.BeatmapInfo.Difficulty); diff --git a/osu.Game/Rulesets/Beatmaps/BeatmapConverter.cs b/osu.Game/Rulesets/Beatmaps/BeatmapConverter.cs index 07aae6a26e..5342686c3f 100644 --- a/osu.Game/Rulesets/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Rulesets/Beatmaps/BeatmapConverter.cs @@ -26,19 +26,21 @@ namespace osu.Game.Rulesets.Beatmaps /// Converts a Beatmap using this Beatmap Converter. /// /// The un-converted Beatmap. + /// Whether to assume the beatmap is for the current ruleset. /// The converted Beatmap. - public Beatmap Convert(Beatmap original) + public Beatmap Convert(Beatmap original, bool isForCurrentRuleset) { // We always operate on a clone of the original beatmap, to not modify it game-wide - return ConvertBeatmap(new Beatmap(original)); + return ConvertBeatmap(new Beatmap(original), isForCurrentRuleset); } /// /// Performs the conversion of a Beatmap using this Beatmap Converter. /// /// The un-converted Beatmap. + /// Whether to assume the beatmap is for the current ruleset. /// The converted Beatmap. - protected virtual Beatmap ConvertBeatmap(Beatmap original) + protected virtual Beatmap ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) { return new Beatmap { diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index ea35e61b36..286ff331d2 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -18,12 +18,13 @@ namespace osu.Game.Rulesets public abstract IEnumerable GetModsFor(ModType type); /// - /// Attempt to create a HitRenderer for the provided beatmap. + /// Attempt to create a hit renderer for a beatmap /// - /// + /// The beatmap to create the hit renderer for. + /// Whether the hit renderer should assume the beatmap is for the current ruleset. /// Unable to successfully load the beatmap to be usable with this ruleset. /// - public abstract HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap); + public abstract HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset); public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap); diff --git a/osu.Game/Rulesets/UI/HitRenderer.cs b/osu.Game/Rulesets/UI/HitRenderer.cs index 3ec5c353a0..d0cce87e43 100644 --- a/osu.Game/Rulesets/UI/HitRenderer.cs +++ b/osu.Game/Rulesets/UI/HitRenderer.cs @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.UI /// protected abstract bool AllObjectsJudged { get; } - protected HitRenderer() + internal HitRenderer() { KeyConversionInputManager = CreateKeyConversionInputManager(); KeyConversionInputManager.RelativeSizeAxes = Axes.Both; @@ -120,7 +120,12 @@ namespace osu.Game.Rulesets.UI /// public Beatmap Beatmap; - protected HitRenderer(WorkingBeatmap beatmap) + /// + /// Creates a hit renderer for a beatmap. + /// + /// The beatmap to create the hit renderer for. + /// Whether to assume the beatmap is for the current ruleset. + internal HitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) { Debug.Assert(beatmap != null, "HitRenderer initialized with a null beatmap."); @@ -134,7 +139,7 @@ namespace osu.Game.Rulesets.UI throw new BeatmapInvalidForRulesetException($"{nameof(Beatmap)} can't be converted for the current ruleset."); // Convert the beatmap - Beatmap = converter.Convert(beatmap.Beatmap); + Beatmap = converter.Convert(beatmap.Beatmap, isForCurrentRuleset); // Apply defaults foreach (var h in Beatmap.HitObjects) @@ -201,8 +206,13 @@ namespace osu.Game.Rulesets.UI private readonly List> drawableObjects = new List>(); - protected HitRenderer(WorkingBeatmap beatmap) - : base(beatmap) + /// + /// Creates a hit renderer for a beatmap. + /// + /// The beatmap to create the hit renderer for. + /// Whether to assume the beatmap is for the current ruleset. + protected HitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) + : base(beatmap, isForCurrentRuleset) { InputManager.Add(content = new Container { diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index d9585b8c04..af6ac5fb33 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -89,7 +89,7 @@ namespace osu.Game.Screens.Play try { - HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap); + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, false); } catch (BeatmapInvalidForRulesetException) { @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Play // let's try again forcing the beatmap's ruleset. ruleset = Beatmap.BeatmapInfo.Ruleset; rulesetInstance = ruleset.CreateInstance(); - HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap); + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, true); } if (!HitRenderer.Objects.Any()) From 9191c4f3e3f4dc64e6d5151f2f3cc8e6df050703 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 16:31:05 +0900 Subject: [PATCH 29/34] Remove LegacyBeatmapConverter. --- .../Beatmaps/LegacyBeatmapConverter.cs | 146 ------------------ .../Beatmaps/ManiaBeatmapConverter.cs | 118 ++++++++++++-- .../osu.Game.Rulesets.Mania.csproj | 1 - osu.Game/Screens/Play/Player.cs | 2 +- 4 files changed, 108 insertions(+), 159 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs diff --git a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs deleted file mode 100644 index e3045df185..0000000000 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System; -using System.Collections.Generic; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Mania.Beatmaps.Patterns; -using osu.Game.Rulesets.Mania.MathUtils; - -namespace osu.Game.Rulesets.Mania.Beatmaps -{ - /// - /// Special converter used for converting from osu!stable beatmaps. - /// - internal class LegacyBeatmapConverter - { - private Pattern lastPattern = new Pattern(); - - private readonly FastRandom random; - private readonly Beatmap beatmap; - - public LegacyBeatmapConverter(Beatmap beatmap) - { - this.beatmap = beatmap; - - int seed = (int)Math.Round(beatmap.BeatmapInfo.Difficulty.DrainRate + beatmap.BeatmapInfo.Difficulty.CircleSize) - * 20 + (int)(beatmap.BeatmapInfo.Difficulty.OverallDifficulty * 41.2) + (int)Math.Round(beatmap.BeatmapInfo.Difficulty.ApproachRate); - random = new FastRandom(seed); - } - - public IEnumerable Convert(HitObject original) - { - var maniaOriginal = original as ManiaHitObject; - if (maniaOriginal != null) - { - yield return maniaOriginal; - yield break; - } - - IEnumerable objects; - switch (beatmap.BeatmapInfo.RulesetID) - { - default: - objects = generateConverted(original); - break; - case 3: - objects = generateSpecific(original); - break; - } - - if (objects == null) - yield break; - - foreach (ManiaHitObject obj in objects) - yield return obj; - } - - private IEnumerable generateSpecific(HitObject original) - { - var generator = new SpecificPatternGenerator(random, original, beatmap, lastPattern); - - Pattern newPattern = generator.Generate(); - lastPattern = newPattern; - - return newPattern.HitObjects; - } - - private IEnumerable generateConverted(HitObject original) - { - var endTimeData = original as IHasEndTime; - var distanceData = original as IHasDistance; - var positionData = original as IHasPosition; - - // Following lines currently commented out to appease resharper - - //PatternGenerator conversion = null; - - if (distanceData != null) - { - // Slider - } - else if (endTimeData != null) - { - // Spinner - } - else if (positionData != null) - { - // Circle - } - - //if (conversion == null) - return null; - - //Pattern newPattern = conversion.Generate(); - //lastPattern = newPattern; - - //return newPattern.HitObjects; - } - - /// - /// A pattern generator for mania-specific beatmaps. - /// - private class SpecificPatternGenerator : Patterns.Legacy.PatternGenerator - { - public SpecificPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) - : base(random, hitObject, beatmap, previousPattern) - { - } - - public override Pattern Generate() - { - var endTimeData = HitObject as IHasEndTime; - var positionData = HitObject as IHasXPosition; - - int column = GetColumn(positionData?.X ?? 0); - - var pattern = new Pattern(); - - if (endTimeData != null) - { - pattern.Add(new HoldNote - { - StartTime = HitObject.StartTime, - Samples = HitObject.Samples, - Duration = endTimeData.Duration, - Column = column, - }); - } - else if (positionData != null) - { - pattern.Add(new Note - { - StartTime = HitObject.StartTime, - Samples = HitObject.Samples, - Column = column - }); - } - - return pattern; - } - } - } -} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 9740c3279d..ed040bdc30 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -9,6 +9,9 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using System.Linq; +using osu.Game.Rulesets.Mania.Beatmaps.Patterns; +using osu.Game.Rulesets.Mania.MathUtils; +using osu.Game.Database; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -16,19 +19,20 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; + private Pattern lastPattern = new Pattern(); + private FastRandom random; + private bool isForCurrentRuleset; + protected override Beatmap ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) { + this.isForCurrentRuleset = isForCurrentRuleset; - // Todo: This should be cased when we get better conversion methods - var converter = new LegacyBeatmapConverter(original); + BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty; - return new Beatmap - { - BeatmapInfo = original.BeatmapInfo, - TimingInfo = original.TimingInfo, - // We need to sort here, because the converter generates patterns - HitObjects = original.HitObjects.SelectMany(converter.Convert).OrderBy(h => h.StartTime).ToList() - }; + int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); + random = new FastRandom(seed); + + return base.ConvertBeatmap(original, isForCurrentRuleset); } protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) @@ -40,10 +44,102 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield break; } + IEnumerable objects; + if (isForCurrentRuleset) + objects = generateSpecific(original, beatmap); + else + objects = generateConverted(original, beatmap); + if (objects == null) + yield break; - // Handled by the LegacyConvereter - yield return null; + foreach (ManiaHitObject obj in objects) + yield return obj; + } + + private IEnumerable generateSpecific(HitObject original, Beatmap beatmap) + { + var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern); + + Pattern newPattern = generator.Generate(); + lastPattern = newPattern; + + return newPattern.HitObjects; + } + + private IEnumerable generateConverted(HitObject original, Beatmap beatmap) + { + var endTimeData = original as IHasEndTime; + var distanceData = original as IHasDistance; + var positionData = original as IHasPosition; + + // Following lines currently commented out to appease resharper + + //Patterns.PatternGenerator conversion = null; + + if (distanceData != null) + { + // Slider + } + else if (endTimeData != null) + { + // Spinner + } + else if (positionData != null) + { + // Circle + } + + //if (conversion == null) + return null; + + //Pattern newPattern = conversion.Generate(); + //lastPattern = newPattern; + + //return newPattern.HitObjects; + } + + /// + /// A pattern generator for mania-specific beatmaps. + /// + private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator + { + public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern) + : base(random, hitObject, beatmap, previousPattern) + { + } + + public override Pattern Generate() + { + var endTimeData = HitObject as IHasEndTime; + var positionData = HitObject as IHasXPosition; + + int column = GetColumn(positionData?.X ?? 0); + + var pattern = new Pattern(); + + if (endTimeData != null) + { + pattern.Add(new HoldNote + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Duration = endTimeData.Duration, + Column = column, + }); + } + else if (positionData != null) + { + pattern.Add(new Note + { + StartTime = HitObject.StartTime, + Samples = HitObject.Samples, + Column = column + }); + } + + return pattern; + } } } } diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index ea65588a81..ec426c895f 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -49,7 +49,6 @@ - diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index af6ac5fb33..e9536c7c00 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -89,7 +89,7 @@ namespace osu.Game.Screens.Play try { - HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, false); + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.BeatmapInfo.Ruleset.ID); } catch (BeatmapInvalidForRulesetException) { From 2cea5f0fa39531993a43b5737ae553601a9b2cf8 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 16:39:02 +0900 Subject: [PATCH 30/34] Add comments. --- .../Beatmaps/ManiaBeatmapConverter.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index ed040bdc30..7d68723b08 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -57,6 +57,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield return obj; } + /// + /// Method that generates hit objects for osu!mania specific beatmaps. + /// + /// The original hit object. + /// The beatmap. + /// The hit objects generated. private IEnumerable generateSpecific(HitObject original, Beatmap beatmap) { var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern); @@ -67,6 +73,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps return newPattern.HitObjects; } + /// + /// Method that generates hit objects for non-osu!mania beatmaps. + /// + /// The original hit object. + /// The beatmap. + /// The hit objects generated. private IEnumerable generateConverted(HitObject original, Beatmap beatmap) { var endTimeData = original as IHasEndTime; @@ -100,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps } /// - /// A pattern generator for mania-specific beatmaps. + /// A pattern generator for osu!mania-specific beatmaps. /// private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator { From 6821197a6ac287edbbb0af0e47837cc5af9df31b Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 16:40:01 +0900 Subject: [PATCH 31/34] Fix converters possibly not converting from new-style beatmaps that hold mode-specific objects. --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs | 2 +- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 2 +- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index f9859cd244..24b364bc06 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { internal class CatchBeatmapConverter : BeatmapConverter { - protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition), typeof(CatchBaseHit) }; protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 7d68723b08..6c717375a0 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { public class ManiaBeatmapConverter : BeatmapConverter { - protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition), typeof(ManiaHitObject) }; private Pattern lastPattern = new Pattern(); private FastRandom random; diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index 7f6f524a7a..bb665c539a 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { internal class OsuBeatmapConverter : BeatmapConverter { - protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasPosition) }; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasPosition), typeof(OsuHitObject) }; protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { From 1cb3fc72622486f5fae3deb2eacbeb233572bc6a Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 16:45:06 +0900 Subject: [PATCH 32/34] Oops fix unused using. --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 6c717375a0..86ce698170 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; -using System.Linq; using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Database; From 860b607f45aa46a943ea873e1274d41b8363df41 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 16:49:05 +0900 Subject: [PATCH 33/34] A bit more cleanup. --- .../Beatmaps/ManiaBeatmapConverter.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 86ce698170..6bdf913c83 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -20,12 +20,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps private Pattern lastPattern = new Pattern(); private FastRandom random; + private Beatmap beatmap; private bool isForCurrentRuleset; protected override Beatmap ConvertBeatmap(Beatmap original, bool isForCurrentRuleset) { this.isForCurrentRuleset = isForCurrentRuleset; + beatmap = original; + BeatmapDifficulty difficulty = original.BeatmapInfo.Difficulty; int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); @@ -43,11 +46,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps yield break; } - IEnumerable objects; - if (isForCurrentRuleset) - objects = generateSpecific(original, beatmap); - else - objects = generateConverted(original, beatmap); + var objects = isForCurrentRuleset ? generateSpecific(original) : generateConverted(original); if (objects == null) yield break; @@ -60,9 +59,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// Method that generates hit objects for osu!mania specific beatmaps. /// /// The original hit object. - /// The beatmap. /// The hit objects generated. - private IEnumerable generateSpecific(HitObject original, Beatmap beatmap) + private IEnumerable generateSpecific(HitObject original) { var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern); @@ -76,9 +74,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// Method that generates hit objects for non-osu!mania beatmaps. /// /// The original hit object. - /// The beatmap. /// The hit objects generated. - private IEnumerable generateConverted(HitObject original, Beatmap beatmap) + private IEnumerable generateConverted(HitObject original) { var endTimeData = original as IHasEndTime; var distanceData = original as IHasDistance; From 7b05930fc2d9a815920e717b08f1571ada0e22b3 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 19 May 2017 17:38:06 +0900 Subject: [PATCH 34/34] Revert "Fix converters possibly not converting from new-style beatmaps that hold mode-specific objects." This reverts commit 6821197a6ac287edbbb0af0e47837cc5af9df31b. --- osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs | 2 +- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs | 2 +- osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs index 24b364bc06..f9859cd244 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapConverter.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps { internal class CatchBeatmapConverter : BeatmapConverter { - protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition), typeof(CatchBaseHit) }; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 6bdf913c83..933fe0787c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { public class ManiaBeatmapConverter : BeatmapConverter { - protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition), typeof(ManiaHitObject) }; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; private Pattern lastPattern = new Pattern(); private FastRandom random; diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs index bb665c539a..7f6f524a7a 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapConverter.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { internal class OsuBeatmapConverter : BeatmapConverter { - protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasPosition), typeof(OsuHitObject) }; + protected override IEnumerable ValidConversionTypes { get; } = new[] { typeof(IHasPosition) }; protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) {