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/LegacyBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs deleted file mode 100644 index de826063b0..0000000000 --- a/osu.Game.Rulesets.Mania/Beatmaps/LegacyBeatmapConverter.cs +++ /dev/null @@ -1,148 +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; -using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; - -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 - - Patterns.PatternGenerator conversion = null; - - if (distanceData != null) - { - conversion = new DistanceObjectPatternGenerator(random, original, beatmap, lastPattern); - // 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 aea77cd2b5..933fe0787c 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -8,7 +8,9 @@ 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; namespace osu.Game.Rulesets.Mania.Beatmaps { @@ -16,24 +18,136 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { 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 LegacyBeatmapConverter(original); + private Pattern lastPattern = new Pattern(); + private FastRandom random; + private Beatmap beatmap; + private bool isForCurrentRuleset; - 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() - }; + 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); + random = new FastRandom(seed); + + return base.ConvertBeatmap(original, isForCurrentRuleset); } protected override IEnumerable ConvertHitObject(HitObject original, Beatmap beatmap) { - // Handled by the LegacyConvereter - yield return null; + var maniaOriginal = original as ManiaHitObject; + if (maniaOriginal != null) + { + yield return maniaOriginal; + yield break; + } + + var objects = isForCurrentRuleset ? generateSpecific(original) : generateConverted(original); + + if (objects == null) + yield break; + + foreach (ManiaHitObject obj in objects) + yield return obj; + } + + /// + /// Method that generates hit objects for osu!mania specific beatmaps. + /// + /// The original hit object. + /// The hit objects generated. + private IEnumerable generateSpecific(HitObject original) + { + var generator = new SpecificBeatmapPatternGenerator(random, original, beatmap, lastPattern); + + Pattern newPattern = generator.Generate(); + lastPattern = newPattern; + + return newPattern.HitObjects; + } + + /// + /// Method that generates hit objects for non-osu!mania beatmaps. + /// + /// The original hit object. + /// The hit objects generated. + 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 + + //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 osu!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/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.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index 9de9cd703f..2497826965 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -50,7 +50,6 @@ - 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..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); + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.BeatmapInfo.Ruleset.ID); } 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())