diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs index a458771550..d4c2c0f0af 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs @@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor protected CatchSelectionBlueprintTestScene() { - EditorBeatmap = new EditorBeatmap(new CatchBeatmap()); - EditorBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = 0; + EditorBeatmap = new EditorBeatmap(new CatchBeatmap()) { Difficulty = { CircleSize = 0 } }; EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 100 diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs index e3811b7669..cca3701a60 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Catch.Edit.Blueprints; using osu.Game.Rulesets.Catch.Edit.Blueprints.Components; @@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor protected override void AddHitObject(DrawableHitObject hitObject) { // Create nested bananas (but positions are not randomized because beatmap processing is not done). - hitObject.HitObject.ApplyDefaults(new ControlPointInfo(), Beatmap.Value.BeatmapInfo.BaseDifficulty); + hitObject.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); base.AddHitObject(hitObject); } diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs index cd1fa31b61..981efc9a13 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Utils; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Edit.Blueprints; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; @@ -23,11 +23,12 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor private JuiceStream lastObject => LastObject?.HitObject as JuiceStream; - [BackgroundDependencyLoader] - private void load() + protected override IBeatmap GetPlayableBeatmap() { - Beatmap.Value.BeatmapInfo.BaseDifficulty.SliderTickRate = 5; - Beatmap.Value.BeatmapInfo.BaseDifficulty.SliderMultiplier = velocity * 10; + var playable = base.GetPlayableBeatmap(); + playable.Difficulty.SliderTickRate = 5; + playable.Difficulty.SliderMultiplier = velocity * 10; + return playable; } [Test] diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs index 5e73a89069..155d033dd0 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs @@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor X = x, Path = sliderPath, }; - EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = velocity; + EditorBeatmap.Difficulty.SliderMultiplier = velocity; EditorBeatmap.Add(hitObject); EditorBeatmap.Update(hitObject); Assert.That(hitObject.Velocity, Is.EqualTo(velocity)); diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index a891ec6c0a..87cc2c45e8 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -211,7 +211,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps palpableObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); - double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) / 2; + double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.Difficulty) / 2; // Todo: This is wrong. osu!stable calculated hyperdashes using the full catcher size, excluding the margins. // This should theoretically cause impossible scenarios, but practically, likely due to the size of the playfield, it doesn't seem possible. diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs index 5b1f613f8d..03a76f10ef 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty return new CatchDifficultyAttributes { Mods = mods, Skills = skills }; // this is the same as osu!, so there's potential to share the implementation... maybe - double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate; + double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; return new CatchDifficultyAttributes { @@ -69,10 +69,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { - halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) * 0.5f; + halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.Difficulty) * 0.5f; // For circle sizes above 5.5, reduce the catcher width further to simulate imperfect gameplay. - halfCatcherWidth *= 1 - (Math.Max(0, beatmap.BeatmapInfo.BaseDifficulty.CircleSize - 5.5f) * 0.0625f); + halfCatcherWidth *= 1 - (Math.Max(0, beatmap.Difficulty.CircleSize - 5.5f) * 0.0625f); return new Skill[] { diff --git a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs index 0344709d45..9a7528d90c 100644 --- a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs +++ b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs @@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Catch.Edit { } - protected override Playfield CreatePlayfield() => new CatchEditorPlayfield(Beatmap.BeatmapInfo.BaseDifficulty); + protected override Playfield CreatePlayfield() => new CatchEditorPlayfield(Beatmap.Difficulty); } } diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index ba6e9224c9..a8ec9f1d2f 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -27,14 +27,14 @@ namespace osu.Game.Rulesets.Catch.UI : base(ruleset, beatmap, mods) { Direction.Value = ScrollingDirection.Down; - TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450); + TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450); } protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield); - protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty); + protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.Difficulty); public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer(); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 01e44ef9e4..ebfbaccd31 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -42,8 +42,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps { IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); - var roundedCircleSize = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize); - var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + var roundedCircleSize = Math.Round(beatmap.Difficulty.CircleSize); + var roundedOverallDifficulty = Math.Round(beatmap.Difficulty.OverallDifficulty); if (IsForCurrentRuleset) { @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps protected override Beatmap ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken) { - IBeatmapDifficultyInfo difficulty = original.BeatmapInfo.BaseDifficulty; + IBeatmapDifficultyInfo difficulty = original.Difficulty; int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate); Random = new FastRandom(seed); diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 26e5d381e2..380efff69f 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy StartTime = (int)Math.Round(hitObject.StartTime); // This matches stable's calculation. - EndTime = (int)Math.Floor(StartTime + distanceData.Distance * beatLength * SpanCount * 0.01 / beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier); + EndTime = (int)Math.Floor(StartTime + distanceData.Distance * beatLength * SpanCount * 0.01 / beatmap.Difficulty.SliderMultiplier); SegmentDuration = (EndTime - StartTime) / SpanCount; } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index d65e78bb49..eaf0ea0f2b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy if (drainTime == 0) drainTime = 10000; - IBeatmapDifficultyInfo difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty; + IBeatmapDifficultyInfo difficulty = OriginalBeatmap.Difficulty; conversionDifficulty = ((difficulty.DrainRate + Math.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index fc29eadedc..9140e8afce 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty return new ManiaDifficultyAttributes { Mods = mods, Skills = skills }; HitWindows hitWindows = new ManiaHitWindows(); - hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); return new ManiaDifficultyAttributes { diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 614a7b00c7..3b7da8d9ba 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.UI { // Mania doesn't care about global velocity p.Velocity = 1; - p.BaseBeatLength *= Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier; + p.BaseBeatLength *= Beatmap.Difficulty.SliderMultiplier; // For non-mania beatmap, speed changes should only happen through timing points if (!isForCurrentRuleset) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs index 9af2a99470..851be2b2f2 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [SetUp] public void Setup() => Schedule(() => { - editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1; + editorBeatmap.Difficulty.SliderMultiplier = 1; editorBeatmap.ControlPointInfo.Clear(); editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length }); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index 41d9bf7132..f09aad8b49 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddSliderStep("circle size", 0f, 10f, 0f, val => { config.SetValue(OsuSetting.AutoCursorSize, true); - gameplayState.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = val; + gameplayState.Beatmap.Difficulty.CircleSize = val; Scheduler.AddOnce(() => loadContent(false)); }); @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Osu.Tests public void TestSizing(int circleSize, float userScale) { AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, userScale)); - AddStep($"adjust cs to {circleSize}", () => gameplayState.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSize); + AddStep($"adjust cs to {circleSize}", () => gameplayState.Beatmap.Difficulty.CircleSize = circleSize); AddStep("turn on autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, true)); AddStep("load content", () => loadContent()); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs index af67ab5839..a5629119b6 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests }; var hitWindows = new OsuHitWindows(); - hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); CreateModTest(new ModTestData { @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests }; var hitWindows = new OsuHitWindows(); - hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); CreateModTest(new ModTestData { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs index cfce80a2b2..ececfb0586 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs @@ -400,9 +400,9 @@ namespace osu.Game.Rulesets.Osu.Tests Beatmap.Value = CreateWorkingBeatmap(new Beatmap { HitObjects = hitObjects, + Difficulty = new BeatmapDifficulty { SliderTickRate = 3 }, BeatmapInfo = { - BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 }, Ruleset = new OsuRuleset().RulesetInfo }, }); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index a8f10f44dc..17a611817c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double starRating = basePerformance > 0.00001 ? Math.Cbrt(1.12) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0; - double preempt = (int)IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / clockRate; + double preempt = (int)IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; int maxCombo = beatmap.HitObjects.Count; // Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above) @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { HitWindows hitWindows = new OsuHitWindows(); - hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); // Todo: These int casts are temporary to achieve 1:1 results with osu!stable, and should be removed in the future hitWindowGreat = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate; diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs index 0d0c3d9e69..f0aade1b7f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - double od = context.Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty; + double od = context.Beatmap.Difficulty.OverallDifficulty; // These are meant to reflect the duration necessary for auto to score at least 1000 points on the spinner. // It's difficult to eliminate warnings here, as auto achieving 1000 points depends on the approach angle on some spinners. diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index b0c655b106..bf70a63ab5 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Osu.Mods .Select(beat => { var newCircle = new HitCircle(); - newCircle.ApplyDefaults(controlPointInfo, osuBeatmap.BeatmapInfo.BaseDifficulty); + newCircle.ApplyDefaults(controlPointInfo, osuBeatmap.Difficulty); newCircle.StartTime = beat; return (OsuHitObject)newCircle; }).ToList(); diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs index b88bf9108b..e231550e3e 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Replays : base(beatmap, mods) { defaultHitWindows = new OsuHitWindows(); - defaultHitWindows.SetDifficulty(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + defaultHitWindows.SetDifficulty(Beatmap.Difficulty.OverallDifficulty); } #endregion diff --git a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs index cb769c31b8..24a660e69e 100644 --- a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs +++ b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs @@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Osu.Statistics return; // Todo: This should probably not be done like this. - float radius = OsuHitObject.OBJECT_RADIUS * (1.0f - 0.7f * (playableBeatmap.BeatmapInfo.BaseDifficulty.CircleSize - 5) / 5) / 2; + float radius = OsuHitObject.OBJECT_RADIUS * (1.0f - 0.7f * (playableBeatmap.Difficulty.CircleSize - 5) / 5) / 2; foreach (var e in score.HitEvents.Where(e => e.HitObject is HitCircle && !(e.HitObject is SliderTailCircle))) { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index cfe83d0106..d1d9ee9f4d 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor if (autoCursorScale.Value && state != null) { // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= GetScaleForCircleSize(state.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize); + scale *= GetScaleForCircleSize(state.Beatmap.Difficulty.CircleSize); } cursorScale.Value = scale; diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 3b5b972c01..ef8cf5cb53 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Utils; using System.Threading; +using JetBrains.Annotations; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Formats; @@ -46,11 +47,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps protected override Beatmap ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken) { - if (!(original.BeatmapInfo.BaseDifficulty is TaikoMutliplierAppliedDifficulty)) + if (!(original.Difficulty is TaikoMutliplierAppliedDifficulty)) { // Rewrite the beatmap info to add the slider velocity multiplier - original.BeatmapInfo = original.BeatmapInfo.Clone(); - original.BeatmapInfo.BaseDifficulty = new TaikoMutliplierAppliedDifficulty(original.BeatmapInfo.BaseDifficulty); + original.Difficulty = new TaikoMutliplierAppliedDifficulty(original.Difficulty); } Beatmap converted = base.ConvertBeatmap(original, cancellationToken); @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps StartTime = obj.StartTime, Samples = obj.Samples, Duration = taikoDuration, - TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4 + TickRate = beatmap.Difficulty.SliderTickRate == 3 ? 3 : 4 }; } @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps case IHasDuration endTimeData: { - double hitMultiplier = IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier; + double hitMultiplier = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.OverallDifficulty, 3, 5, 7.5) * swell_hit_multiplier; yield return new Swell { @@ -164,10 +164,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps else beatLength = timingPoint.BeatLength / difficultyPoint.SpeedMultiplier; - double sliderScoringPointDistance = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate; + double sliderScoringPointDistance = osu_base_scoring_distance * beatmap.Difficulty.SliderMultiplier / beatmap.Difficulty.SliderTickRate; // The velocity and duration of the taiko hit object - calculated as the velocity of a drum roll. - double taikoVelocity = sliderScoringPointDistance * beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate; + double taikoVelocity = sliderScoringPointDistance * beatmap.Difficulty.SliderTickRate; taikoDuration = (int)(distance / taikoVelocity * beatLength); if (isForCurrentRuleset) @@ -183,7 +183,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps beatLength = timingPoint.BeatLength; // If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat - tickSpacing = Math.Min(beatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, (double)taikoDuration / spans); + tickSpacing = Math.Min(beatLength / beatmap.Difficulty.SliderTickRate, (double)taikoDuration / spans); return tickSpacing > 0 && distance / osuVelocity * 1000 < 2 * beatLength; @@ -196,9 +196,30 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps public TaikoMutliplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty) { CopyFrom(difficulty); - - SliderMultiplier *= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; } + + [UsedImplicitly] + public TaikoMutliplierAppliedDifficulty() + { + } + + #region Overrides of BeatmapDifficulty + + public override void CopyTo(BeatmapDifficulty other) + { + base.CopyTo(other); + if (!(other is TaikoMutliplierAppliedDifficulty)) + SliderMultiplier /= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; + } + + public override void CopyFrom(IBeatmapDifficultyInfo other) + { + base.CopyFrom(other); + if (!(other is TaikoMutliplierAppliedDifficulty)) + SliderMultiplier *= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; + } + + #endregion } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 18d06c069f..e755bb2325 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty starRating = rescale(starRating); HitWindows hitWindows = new TaikoHitWindows(); - hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); return new TaikoDifficultyAttributes { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs index 94cd411d7b..0d6ce44255 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs @@ -40,8 +40,8 @@ namespace osu.Game.Rulesets.Taiko.Scoring { base.ApplyBeatmap(beatmap); - hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType().Count()) * IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); - hpMissMultiplier = IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); + hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType().Count()) * IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 0.5, 0.75, 0.98)); + hpMissMultiplier = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 0.0018, 0.0075, 0.0120); } protected override double GetHealthIncreaseFor(JudgementResult result) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index a4bf8c92e3..b5e1fa204f 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -129,7 +129,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var stream = new LineBufferedReader(resStream)) { - var difficulty = decoder.Decode(stream).BeatmapInfo.BaseDifficulty; + var difficulty = decoder.Decode(stream).Difficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 1fc3abef9a..9ec2f37569 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Beatmaps.Formats public void TestDecodeDifficulty() { var beatmap = decodeAsJson(normal); - var difficulty = beatmap.BeatmapInfo.BaseDifficulty; + var difficulty = beatmap.Difficulty; Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(4, difficulty.CircleSize); Assert.AreEqual(8, difficulty.OverallDifficulty); @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Beatmaps.Formats processor.PreProcess(); foreach (var o in converted.HitObjects) - o.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); + o.ApplyDefaults(converted.ControlPointInfo, converted.Difficulty); processor.PostProcess(); var beatmap = converted.Serialize().Deserialize(); diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index bd34eaff63..a40a6dac4c 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Editing BeatDivisor.Value = 1; - composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1; + composer.EditorBeatmap.Difficulty.SliderMultiplier = 1; composer.EditorBeatmap.ControlPointInfo.Clear(); composer.EditorBeatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 1 }); @@ -64,7 +64,7 @@ namespace osu.Game.Tests.Editing [TestCase(2)] public void TestSliderMultiplier(float multiplier) { - AddStep($"set multiplier = {multiplier}", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = multiplier); + AddStep($"set multiplier = {multiplier}", () => composer.EditorBeatmap.Difficulty.SliderMultiplier = multiplier); assertSnapDistance(100 * multiplier); } @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Editing assertDurationToDistance(500, 50); assertDurationToDistance(1000, 100); - AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2); + AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.Difficulty.SliderMultiplier = 2); assertDurationToDistance(500, 100); assertDurationToDistance(1000, 200); @@ -118,7 +118,7 @@ namespace osu.Game.Tests.Editing assertDistanceToDuration(50, 500); assertDistanceToDuration(100, 1000); - AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2); + AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.Difficulty.SliderMultiplier = 2); assertDistanceToDuration(100, 500); assertDistanceToDuration(200, 1000); @@ -143,7 +143,7 @@ namespace osu.Game.Tests.Editing assertSnappedDuration(200, 2000); assertSnappedDuration(250, 3000); - AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2); + AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.Difficulty.SliderMultiplier = 2); assertSnappedDuration(0, 0); assertSnappedDuration(50, 0); @@ -175,7 +175,7 @@ namespace osu.Game.Tests.Editing assertSnappedDistance(200, 200); assertSnappedDistance(250, 200); - AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2); + AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.Difficulty.SliderMultiplier = 2); assertSnappedDistance(50, 0); assertSnappedDistance(100, 0); diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index 7264083338..296c5cef76 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -165,7 +165,7 @@ namespace osu.Game.Tests.Gameplay { var beatmap = new Beatmap { - BeatmapInfo = { BaseDifficulty = { DrainRate = 10 } }, + Difficulty = { DrainRate = 10 } }; beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 }); @@ -200,7 +200,7 @@ namespace osu.Game.Tests.Gameplay { var beatmap = new Beatmap { - BeatmapInfo = { BaseDifficulty = { DrainRate = 10 } }, + Difficulty = { DrainRate = 10 } }; for (double time = startTime; time <= endTime; time += 100) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 75a5eec6f7..3f10d7892d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -182,7 +182,7 @@ namespace osu.Game.Tests.Visual.Gameplay { var beatmap = createBeatmap(); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range }); - beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; + beatmap.Difficulty.SliderMultiplier = 2; createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true); AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 5000); @@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual.Gameplay { var beatmap = createBeatmap(); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range }); - beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; + beatmap.Difficulty.SliderMultiplier = 2; createTest(beatmap); AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 2000); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index 73c6970482..814b41cdbc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Gameplay { var beatmap = new Beatmap { - BeatmapInfo = { BaseDifficulty = { ApproachRate = 9 } }, + Difficulty = { ApproachRate = 9 }, }; for (int i = 0; i < 15; i++) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index d8ec89a94e..deb9a22184 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -137,11 +137,11 @@ namespace osu.Game.Tests.Visual.Playlists InputManager.Click(MouseButton.Left); }); - AddAssert("match has altered beatmap", () => match.Beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize == 1); + AddAssert("match has altered beatmap", () => match.Beatmap.Value.Beatmap.Difficulty.CircleSize == 1); AddStep("re-import original beatmap", () => manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait()); - AddAssert("match has original beatmap", () => match.Beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize != 1); + AddAssert("match has original beatmap", () => match.Beatmap.Value.Beatmap.Difficulty.CircleSize != 1); } private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index e5b6a4bc44..b2211e26cf 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -18,17 +18,48 @@ namespace osu.Game.Beatmaps public class Beatmap : IBeatmap where T : HitObject { - public BeatmapInfo BeatmapInfo { get; set; } = new BeatmapInfo + private BeatmapDifficulty difficulty = new BeatmapDifficulty(); + + public BeatmapDifficulty Difficulty { - Metadata = new BeatmapMetadata + get => difficulty; + set { - Artist = @"Unknown", - Title = @"Unknown", - AuthorString = @"Unknown Creator", - }, - Version = @"Normal", - BaseDifficulty = new BeatmapDifficulty() - }; + difficulty = value; + + if (beatmapInfo != null) + beatmapInfo.BaseDifficulty = difficulty.Clone(); + } + } + + private BeatmapInfo beatmapInfo; + + public BeatmapInfo BeatmapInfo + { + get => beatmapInfo; + set + { + beatmapInfo = value; + + if (beatmapInfo?.BaseDifficulty != null) + Difficulty = beatmapInfo.BaseDifficulty.Clone(); + } + } + + public Beatmap() + { + beatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata + { + Artist = @"Unknown", + Title = @"Unknown", + AuthorString = @"Unknown Creator", + }, + Version = @"Normal", + BaseDifficulty = Difficulty, + }; + } [JsonIgnore] public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index 2bb0787b4c..dfd21469fa 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Game.Database; namespace osu.Game.Beatmaps @@ -43,31 +44,31 @@ namespace osu.Game.Beatmaps /// public BeatmapDifficulty Clone() { - var diff = new BeatmapDifficulty(); + var diff = (BeatmapDifficulty)Activator.CreateInstance(GetType()); CopyTo(diff); return diff; } - public void CopyFrom(IBeatmapDifficultyInfo difficulty) + public virtual void CopyFrom(IBeatmapDifficultyInfo other) { - ApproachRate = difficulty.ApproachRate; - DrainRate = difficulty.DrainRate; - CircleSize = difficulty.CircleSize; - OverallDifficulty = difficulty.OverallDifficulty; + ApproachRate = other.ApproachRate; + DrainRate = other.DrainRate; + CircleSize = other.CircleSize; + OverallDifficulty = other.OverallDifficulty; - SliderMultiplier = difficulty.SliderMultiplier; - SliderTickRate = difficulty.SliderTickRate; + SliderMultiplier = other.SliderMultiplier; + SliderTickRate = other.SliderTickRate; } - public void CopyTo(BeatmapDifficulty difficulty) + public virtual void CopyTo(BeatmapDifficulty other) { - difficulty.ApproachRate = ApproachRate; - difficulty.DrainRate = DrainRate; - difficulty.CircleSize = CircleSize; - difficulty.OverallDifficulty = OverallDifficulty; + other.ApproachRate = ApproachRate; + other.DrainRate = DrainRate; + other.CircleSize = CircleSize; + other.OverallDifficulty = OverallDifficulty; - difficulty.SliderMultiplier = SliderMultiplier; - difficulty.SliderTickRate = SliderTickRate; + other.SliderMultiplier = SliderMultiplier; + other.SliderTickRate = SliderTickRate; } } } diff --git a/osu.Game/Beatmaps/BeatmapModelManager.cs b/osu.Game/Beatmaps/BeatmapModelManager.cs index 787559899a..9c0fc5ef8a 100644 --- a/osu.Game/Beatmaps/BeatmapModelManager.cs +++ b/osu.Game/Beatmaps/BeatmapModelManager.cs @@ -202,6 +202,8 @@ namespace osu.Game.Beatmaps using (ContextFactory.GetForWrite()) { beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == beatmapInfo.ID); + beatmapInfo.BaseDifficulty.CopyFrom(beatmapContent.Difficulty); + var metadata = beatmapInfo.Metadata ?? setInfo.Metadata; // grab the original file (or create a new one if not found). diff --git a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs index 988968fa42..0d5c48f64d 100644 --- a/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/JsonBeatmapDecoder.cs @@ -18,7 +18,7 @@ namespace osu.Game.Beatmaps.Formats stream.ReadToEnd().DeserializeInto(output); foreach (var hitObject in output.HitObjects) - hitObject.ApplyDefaults(output.ControlPointInfo, output.BeatmapInfo.BaseDifficulty); + hitObject.ApplyDefaults(output.ControlPointInfo, output.Difficulty); } } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 4b5eaafa4a..f71b148008 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -67,7 +67,7 @@ namespace osu.Game.Beatmaps.Formats this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList(); foreach (var hitObject in this.beatmap.HitObjects) - hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty); + hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.Difficulty); } protected override bool ShouldSkipLine(string line) => base.ShouldSkipLine(line) || line.StartsWith(' ') || line.StartsWith('_'); @@ -276,7 +276,7 @@ namespace osu.Game.Beatmaps.Formats { var pair = SplitKeyVal(line); - var difficulty = beatmap.BeatmapInfo.BaseDifficulty; + var difficulty = beatmap.Difficulty; switch (pair.Key) { @@ -444,7 +444,7 @@ namespace osu.Game.Beatmaps.Formats if (obj != null) { - obj.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + obj.ApplyDefaults(beatmap.ControlPointInfo, beatmap.Difficulty); beatmap.HitObjects.Add(obj); } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index aef13b8872..74b3c178cd 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -141,17 +141,17 @@ namespace osu.Game.Beatmaps.Formats { writer.WriteLine("[Difficulty]"); - writer.WriteLine(FormattableString.Invariant($"HPDrainRate: {beatmap.BeatmapInfo.BaseDifficulty.DrainRate}")); - writer.WriteLine(FormattableString.Invariant($"CircleSize: {beatmap.BeatmapInfo.BaseDifficulty.CircleSize}")); - writer.WriteLine(FormattableString.Invariant($"OverallDifficulty: {beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty}")); - writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.BeatmapInfo.BaseDifficulty.ApproachRate}")); + writer.WriteLine(FormattableString.Invariant($"HPDrainRate: {beatmap.Difficulty.DrainRate}")); + writer.WriteLine(FormattableString.Invariant($"CircleSize: {beatmap.Difficulty.CircleSize}")); + writer.WriteLine(FormattableString.Invariant($"OverallDifficulty: {beatmap.Difficulty.OverallDifficulty}")); + writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.Difficulty.ApproachRate}")); // Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER) writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1 - ? FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}") - : FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier}")); + ? FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}") + : FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier}")); - writer.WriteLine(FormattableString.Invariant($"SliderTickRate: {beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate}")); + writer.WriteLine(FormattableString.Invariant($"SliderTickRate: {beatmap.Difficulty.SliderTickRate}")); } private void handleEvents(TextWriter writer) @@ -285,7 +285,7 @@ namespace osu.Game.Beatmaps.Formats break; case 3: - int totalColumns = (int)Math.Max(1, beatmap.BeatmapInfo.BaseDifficulty.CircleSize); + int totalColumns = (int)Math.Max(1, beatmap.Difficulty.CircleSize); position.X = (int)Math.Ceiling(((IHasXPosition)hitObject).X * (512f / totalColumns)); break; } diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index f61dd269e1..3f598cd1e5 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -20,6 +20,11 @@ namespace osu.Game.Beatmaps /// BeatmapMetadata Metadata { get; } + /// + /// This beatmap's difficulty settings. + /// + public BeatmapDifficulty Difficulty { get; set; } + /// /// The control points in this beatmap. /// diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index c4c5c89f28..18adecb7aa 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -119,15 +119,12 @@ namespace osu.Game.Beatmaps // Apply difficulty mods if (mods.Any(m => m is IApplicableToDifficulty)) { - converted.BeatmapInfo = converted.BeatmapInfo.Clone(); - converted.BeatmapInfo.BaseDifficulty = converted.BeatmapInfo.BaseDifficulty.Clone(); - foreach (var mod in mods.OfType()) { if (cancellationSource.IsCancellationRequested) throw new BeatmapLoadTimeoutException(BeatmapInfo); - mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); + mod.ApplyToDifficulty(converted.Difficulty); } } @@ -146,7 +143,7 @@ namespace osu.Game.Beatmaps if (cancellationSource.IsCancellationRequested) throw new BeatmapLoadTimeoutException(BeatmapInfo); - obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty, cancellationSource.Token); + obj.ApplyDefaults(converted.ControlPointInfo, converted.Difficulty, cancellationSource.Token); } } catch (OperationCanceledException) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 1143549f7f..200bbf3f92 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -258,6 +258,13 @@ namespace osu.Game.Rulesets.Difficulty } public BeatmapMetadata Metadata => baseBeatmap.Metadata; + + public BeatmapDifficulty Difficulty + { + get => baseBeatmap.Difficulty; + set => baseBeatmap.Difficulty = value; + } + public List Breaks => baseBeatmap.Breaks; public double TotalBreakTime => baseBeatmap.TotalBreakTime; public IEnumerable GetStatistics() => baseBeatmap.GetStatistics(); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 8090fcbd32..b41e0442bc 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -392,7 +392,7 @@ namespace osu.Game.Rulesets.Edit public override float GetBeatSnapDistanceAt(double referenceTime) { DifficultyControlPoint difficultyPoint = EditorBeatmap.ControlPointInfo.DifficultyPointAt(referenceTime); - return (float)(100 * EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / BeatSnapProvider.BeatDivisor); + return (float)(100 * EditorBeatmap.Difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / BeatSnapProvider.BeatDivisor); } public override float DurationToDistance(double referenceTime, double duration) diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index b7529f39ca..0c0c5990d1 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Edit /// Invokes , /// refreshing and parameters for the . /// - protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.ControlPointInfo, beatmap.Difficulty); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false; diff --git a/osu.Game/Rulesets/Mods/DifficultyBindable.cs b/osu.Game/Rulesets/Mods/DifficultyBindable.cs index e4304795f2..6cfae0b085 100644 --- a/osu.Game/Rulesets/Mods/DifficultyBindable.cs +++ b/osu.Game/Rulesets/Mods/DifficultyBindable.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mods /// /// A function that can extract the current value of this setting from a beatmap difficulty for display purposes. /// - public Func ReadCurrentFromDifficulty; + public Func ReadCurrentFromDifficulty; public float Precision { diff --git a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs index 85693abb93..dfeb6b4788 100644 --- a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Scoring .First() ))); - targetMinimumHealth = IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, min_health_target, mid_health_target, max_health_target); + targetMinimumHealth = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, min_health_target, mid_health_target, max_health_target); // Add back a portion of the amount of HP to be drained, depending on the lenience requested. targetMinimumHealth += drainLenience * (1 - targetMinimumHealth); diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 7b30bb9574..041c5ebef5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.UI.Scrolling maxDuration = duration; // The slider multiplier is post-multiplied to determine the final velocity, but for relative scale beat lengths // the multiplier should not affect the effective timing point (the longest in the beatmap), so it is factored out here - baseBeatLength = timingPoints[i].BeatLength / Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier; + baseBeatLength = timingPoints[i].BeatLength / Beatmap.Difficulty.SliderMultiplier; } } } @@ -155,7 +155,7 @@ namespace osu.Game.Rulesets.UI.Scrolling return new MultiplierControlPoint(c.Time) { - Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier, + Velocity = Beatmap.Difficulty.SliderMultiplier, BaseBeatLength = baseBeatLength, TimingPoint = lastTimingPoint, DifficultyPoint = lastDifficultyPoint @@ -172,7 +172,7 @@ namespace osu.Game.Rulesets.UI.Scrolling ControlPoints.AddRange(timingChanges); if (ControlPoints.Count == 0) - ControlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); + ControlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.Difficulty.SliderMultiplier }); } protected override void LoadComplete() diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 3402bf653a..64eb6225fa 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -86,6 +86,12 @@ namespace osu.Game.Screens.Edit public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; + public BeatmapDifficulty Difficulty + { + get => PlayableBeatmap.Difficulty; + set => PlayableBeatmap.Difficulty = value; + } + public ControlPointInfo ControlPointInfo { get => PlayableBeatmap.ControlPointInfo; @@ -286,7 +292,7 @@ namespace osu.Game.Screens.Edit /// public void Clear() => RemoveRange(HitObjects.ToArray()); - private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, BeatmapInfo.BaseDifficulty); + private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty); private void trackStartTime(HitObject hitObject) { diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index a8800d524f..75c6a89a66 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Setup Label = "Object Size", FixedLabelWidth = LABEL_WIDTH, Description = "The size of all hit objects", - Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize) + Current = new BindableFloat(Beatmap.Difficulty.CircleSize) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Edit.Setup Label = "Health Drain", FixedLabelWidth = LABEL_WIDTH, Description = "The rate of passive health drain throughout playable time", - Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.DrainRate) + Current = new BindableFloat(Beatmap.Difficulty.DrainRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit.Setup Label = "Approach Rate", FixedLabelWidth = LABEL_WIDTH, Description = "The speed at which objects are presented to the player", - Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate) + Current = new BindableFloat(Beatmap.Difficulty.ApproachRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -69,7 +69,7 @@ namespace osu.Game.Screens.Edit.Setup Label = "Overall Difficulty", FixedLabelWidth = LABEL_WIDTH, Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)", - Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) + Current = new BindableFloat(Beatmap.Difficulty.OverallDifficulty) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, MinValue = 0, @@ -87,10 +87,10 @@ namespace osu.Game.Screens.Edit.Setup { // for now, update these on commit rather than making BeatmapMetadata bindables. // after switching database engines we can reconsider if switching to bindables is a good direction. - Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value; - Beatmap.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value; - Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value; - Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value; + Beatmap.Difficulty.CircleSize = circleSizeSlider.Current.Value; + Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value; + Beatmap.Difficulty.ApproachRate = approachRateSlider.Current.Value; + Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value; Beatmap.UpdateAllHitObjects(); } diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs index 42cf826bd4..b2f5b1754f 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -24,24 +25,25 @@ namespace osu.Game.Tests.Visual base.Content.Add(HitObjectContainer = CreateHitObjectContainer().With(c => c.Clock = new FramedClock(new StopwatchClock()))); } - [BackgroundDependencyLoader] - private void load() - { - Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = 2; - } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); dependencies.CacheAs(new EditorClock()); - var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); + var playable = GetPlayableBeatmap(); dependencies.CacheAs(new EditorBeatmap(playable)); return dependencies; } + protected virtual IBeatmap GetPlayableBeatmap() + { + var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); + playable.Difficulty.CircleSize = 2; + return playable; + } + protected override void LoadComplete() { base.LoadComplete();