1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-21 08:12:56 +08:00

Merge branch 'master' into popup-filter-effect

This commit is contained in:
Dean Herbert 2021-10-07 18:56:07 +09:00 committed by GitHub
commit ef64c64f0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 206 additions and 159 deletions

View File

@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
protected CatchSelectionBlueprintTestScene() protected CatchSelectionBlueprintTestScene()
{ {
EditorBeatmap = new EditorBeatmap(new CatchBeatmap()); EditorBeatmap = new EditorBeatmap(new CatchBeatmap()) { Difficulty = { CircleSize = 0 } };
EditorBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = 0;
EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint
{ {
BeatLength = 100 BeatLength = 100

View File

@ -5,6 +5,7 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Catch.Edit.Blueprints; using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Edit.Blueprints.Components; 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) protected override void AddHitObject(DrawableHitObject hitObject)
{ {
// Create nested bananas (but positions are not randomized because beatmap processing is not done). // 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); base.AddHitObject(hitObject);
} }

View File

@ -4,9 +4,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Edit.Blueprints; using osu.Game.Rulesets.Catch.Edit.Blueprints;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawables; 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; private JuiceStream lastObject => LastObject?.HitObject as JuiceStream;
[BackgroundDependencyLoader] protected override IBeatmap GetPlayableBeatmap()
private void load()
{ {
Beatmap.Value.BeatmapInfo.BaseDifficulty.SliderTickRate = 5; var playable = base.GetPlayableBeatmap();
Beatmap.Value.BeatmapInfo.BaseDifficulty.SliderMultiplier = velocity * 10; playable.Difficulty.SliderTickRate = 5;
playable.Difficulty.SliderMultiplier = velocity * 10;
return playable;
} }
[Test] [Test]

View File

@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
X = x, X = x,
Path = sliderPath, Path = sliderPath,
}; };
EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = velocity; EditorBeatmap.Difficulty.SliderMultiplier = velocity;
EditorBeatmap.Add(hitObject); EditorBeatmap.Add(hitObject);
EditorBeatmap.Update(hitObject); EditorBeatmap.Update(hitObject);
Assert.That(hitObject.Velocity, Is.EqualTo(velocity)); Assert.That(hitObject.Velocity, Is.EqualTo(velocity));

View File

@ -211,7 +211,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
palpableObjects.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)); 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. // 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. // This should theoretically cause impossible scenarios, but practically, likely due to the size of the playfield, it doesn't seem possible.

View File

@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
return new CatchDifficultyAttributes { Mods = mods, Skills = skills }; return new CatchDifficultyAttributes { Mods = mods, Skills = skills };
// this is the same as osu!, so there's potential to share the implementation... maybe // 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 return new CatchDifficultyAttributes
{ {
@ -69,10 +69,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) 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. // 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[] return new Skill[]
{ {

View File

@ -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);
} }
} }

View File

@ -27,14 +27,14 @@ namespace osu.Game.Rulesets.Catch.UI
: base(ruleset, beatmap, mods) : base(ruleset, beatmap, mods)
{ {
Direction.Value = ScrollingDirection.Down; 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 ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield); 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(); public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchPlayfieldAdjustmentContainer();

View File

@ -42,8 +42,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
{ {
IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo); IsForCurrentRuleset = beatmap.BeatmapInfo.Ruleset.Equals(ruleset.RulesetInfo);
var roundedCircleSize = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize); var roundedCircleSize = Math.Round(beatmap.Difficulty.CircleSize);
var roundedOverallDifficulty = Math.Round(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); var roundedOverallDifficulty = Math.Round(beatmap.Difficulty.OverallDifficulty);
if (IsForCurrentRuleset) if (IsForCurrentRuleset)
{ {
@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken) protected override Beatmap<ManiaHitObject> 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); int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate);
Random = new FastRandom(seed); Random = new FastRandom(seed);

View File

@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
StartTime = (int)Math.Round(hitObject.StartTime); StartTime = (int)Math.Round(hitObject.StartTime);
// This matches stable's calculation. // 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; SegmentDuration = (EndTime - StartTime) / SpanCount;
} }

View File

@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (drainTime == 0) if (drainTime == 0)
drainTime = 10000; 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 = ((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); conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);

View File

@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
return new ManiaDifficultyAttributes { Mods = mods, Skills = skills }; return new ManiaDifficultyAttributes { Mods = mods, Skills = skills };
HitWindows hitWindows = new ManiaHitWindows(); HitWindows hitWindows = new ManiaHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
return new ManiaDifficultyAttributes return new ManiaDifficultyAttributes
{ {

View File

@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
// Mania doesn't care about global velocity // Mania doesn't care about global velocity
p.Velocity = 1; 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 // For non-mania beatmap, speed changes should only happen through timing points
if (!isForCurrentRuleset) if (!isForCurrentRuleset)

View File

@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
[SetUp] [SetUp]
public void Setup() => Schedule(() => public void Setup() => Schedule(() =>
{ {
editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1; editorBeatmap.Difficulty.SliderMultiplier = 1;
editorBeatmap.ControlPointInfo.Clear(); editorBeatmap.ControlPointInfo.Clear();
editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length }); editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });

View File

@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Tests
AddSliderStep("circle size", 0f, 10f, 0f, val => AddSliderStep("circle size", 0f, 10f, 0f, val =>
{ {
config.SetValue(OsuSetting.AutoCursorSize, true); config.SetValue(OsuSetting.AutoCursorSize, true);
gameplayState.Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = val; gameplayState.Beatmap.Difficulty.CircleSize = val;
Scheduler.AddOnce(() => loadContent(false)); Scheduler.AddOnce(() => loadContent(false));
}); });
@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public void TestSizing(int circleSize, float userScale) public void TestSizing(int circleSize, float userScale)
{ {
AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, 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("turn on autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, true));
AddStep("load content", () => loadContent()); AddStep("load content", () => loadContent());

View File

@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests
}; };
var hitWindows = new OsuHitWindows(); var hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
CreateModTest(new ModTestData CreateModTest(new ModTestData
{ {
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests
}; };
var hitWindows = new OsuHitWindows(); var hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
CreateModTest(new ModTestData CreateModTest(new ModTestData
{ {

View File

@ -400,9 +400,9 @@ namespace osu.Game.Rulesets.Osu.Tests
Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject> Beatmap.Value = CreateWorkingBeatmap(new Beatmap<OsuHitObject>
{ {
HitObjects = hitObjects, HitObjects = hitObjects,
Difficulty = new BeatmapDifficulty { SliderTickRate = 3 },
BeatmapInfo = BeatmapInfo =
{ {
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 3 },
Ruleset = new OsuRuleset().RulesetInfo Ruleset = new OsuRuleset().RulesetInfo
}, },
}); });

View File

@ -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 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; 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) // 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) protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate)
{ {
HitWindows hitWindows = new OsuHitWindows(); 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 // 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; hitWindowGreat = (int)(hitWindows.WindowFor(HitResult.Great)) / clockRate;

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
public IEnumerable<Issue> Run(BeatmapVerifierContext context) public IEnumerable<Issue> 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. // 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. // It's difficult to eliminate warnings here, as auto achieving 1000 points depends on the approach angle on some spinners.

View File

@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Osu.Mods
.Select(beat => .Select(beat =>
{ {
var newCircle = new HitCircle(); var newCircle = new HitCircle();
newCircle.ApplyDefaults(controlPointInfo, osuBeatmap.BeatmapInfo.BaseDifficulty); newCircle.ApplyDefaults(controlPointInfo, osuBeatmap.Difficulty);
newCircle.StartTime = beat; newCircle.StartTime = beat;
return (OsuHitObject)newCircle; return (OsuHitObject)newCircle;
}).ToList(); }).ToList();

View File

@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Replays
: base(beatmap, mods) : base(beatmap, mods)
{ {
defaultHitWindows = new OsuHitWindows(); defaultHitWindows = new OsuHitWindows();
defaultHitWindows.SetDifficulty(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); defaultHitWindows.SetDifficulty(Beatmap.Difficulty.OverallDifficulty);
} }
#endregion #endregion

View File

@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Osu.Statistics
return; return;
// Todo: This should probably not be done like this. // 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))) foreach (var e in score.HitEvents.Where(e => e.HitObject is HitCircle && !(e.HitObject is SliderTailCircle)))
{ {

View File

@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
if (autoCursorScale.Value && state != null) 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. // 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; cursorScale.Value = scale;

View File

@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Utils; using osu.Framework.Utils;
using System.Threading; using System.Threading;
using JetBrains.Annotations;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
@ -46,11 +47,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
protected override Beatmap<TaikoHitObject> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken) protected override Beatmap<TaikoHitObject> 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 // Rewrite the beatmap info to add the slider velocity multiplier
original.BeatmapInfo = original.BeatmapInfo.Clone(); original.Difficulty = new TaikoMutliplierAppliedDifficulty(original.Difficulty);
original.BeatmapInfo.BaseDifficulty = new TaikoMutliplierAppliedDifficulty(original.BeatmapInfo.BaseDifficulty);
} }
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken); Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original, cancellationToken);
@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
StartTime = obj.StartTime, StartTime = obj.StartTime,
Samples = obj.Samples, Samples = obj.Samples,
Duration = taikoDuration, 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: 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 yield return new Swell
{ {
@ -164,10 +164,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
else else
beatLength = timingPoint.BeatLength / difficultyPoint.SpeedMultiplier; 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. // 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); taikoDuration = (int)(distance / taikoVelocity * beatLength);
if (isForCurrentRuleset) if (isForCurrentRuleset)
@ -183,7 +183,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
beatLength = timingPoint.BeatLength; 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 // 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 return tickSpacing > 0
&& distance / osuVelocity * 1000 < 2 * beatLength; && distance / osuVelocity * 1000 < 2 * beatLength;
@ -196,9 +196,30 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
public TaikoMutliplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty) public TaikoMutliplierAppliedDifficulty(IBeatmapDifficultyInfo difficulty)
{ {
CopyFrom(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
} }
} }
} }

View File

@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
starRating = rescale(starRating); starRating = rescale(starRating);
HitWindows hitWindows = new TaikoHitWindows(); HitWindows hitWindows = new TaikoHitWindows();
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
return new TaikoDifficultyAttributes return new TaikoDifficultyAttributes
{ {

View File

@ -40,8 +40,8 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{ {
base.ApplyBeatmap(beatmap); base.ApplyBeatmap(beatmap);
hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType<Hit>().Count()) * IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType<Hit>().Count()) * IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 0.5, 0.75, 0.98));
hpMissMultiplier = IBeatmapDifficultyInfo.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120); hpMissMultiplier = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 0.0018, 0.0075, 0.0120);
} }
protected override double GetHealthIncreaseFor(JudgementResult result) protected override double GetHealthIncreaseFor(JudgementResult result)

View File

@ -129,7 +129,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu")) using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new LineBufferedReader(resStream)) 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(6.5f, difficulty.DrainRate);
Assert.AreEqual(4, difficulty.CircleSize); Assert.AreEqual(4, difficulty.CircleSize);

View File

@ -84,7 +84,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
public void TestDecodeDifficulty() public void TestDecodeDifficulty()
{ {
var beatmap = decodeAsJson(normal); var beatmap = decodeAsJson(normal);
var difficulty = beatmap.BeatmapInfo.BaseDifficulty; var difficulty = beatmap.Difficulty;
Assert.AreEqual(6.5f, difficulty.DrainRate); Assert.AreEqual(6.5f, difficulty.DrainRate);
Assert.AreEqual(4, difficulty.CircleSize); Assert.AreEqual(4, difficulty.CircleSize);
Assert.AreEqual(8, difficulty.OverallDifficulty); Assert.AreEqual(8, difficulty.OverallDifficulty);
@ -102,7 +102,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
processor.PreProcess(); processor.PreProcess();
foreach (var o in converted.HitObjects) foreach (var o in converted.HitObjects)
o.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); o.ApplyDefaults(converted.ControlPointInfo, converted.Difficulty);
processor.PostProcess(); processor.PostProcess();
var beatmap = converted.Serialize().Deserialize<Beatmap>(); var beatmap = converted.Serialize().Deserialize<Beatmap>();

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Editing
BeatDivisor.Value = 1; BeatDivisor.Value = 1;
composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1; composer.EditorBeatmap.Difficulty.SliderMultiplier = 1;
composer.EditorBeatmap.ControlPointInfo.Clear(); composer.EditorBeatmap.ControlPointInfo.Clear();
composer.EditorBeatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 1 }); composer.EditorBeatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 1 });
@ -64,7 +64,7 @@ namespace osu.Game.Tests.Editing
[TestCase(2)] [TestCase(2)]
public void TestSliderMultiplier(float multiplier) 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); assertSnapDistance(100 * multiplier);
} }
@ -97,7 +97,7 @@ namespace osu.Game.Tests.Editing
assertDurationToDistance(500, 50); assertDurationToDistance(500, 50);
assertDurationToDistance(1000, 100); 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(500, 100);
assertDurationToDistance(1000, 200); assertDurationToDistance(1000, 200);
@ -118,7 +118,7 @@ namespace osu.Game.Tests.Editing
assertDistanceToDuration(50, 500); assertDistanceToDuration(50, 500);
assertDistanceToDuration(100, 1000); 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(100, 500);
assertDistanceToDuration(200, 1000); assertDistanceToDuration(200, 1000);
@ -143,7 +143,7 @@ namespace osu.Game.Tests.Editing
assertSnappedDuration(200, 2000); assertSnappedDuration(200, 2000);
assertSnappedDuration(250, 3000); 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(0, 0);
assertSnappedDuration(50, 0); assertSnappedDuration(50, 0);
@ -175,7 +175,7 @@ namespace osu.Game.Tests.Editing
assertSnappedDistance(200, 200); assertSnappedDistance(200, 200);
assertSnappedDistance(250, 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(50, 0);
assertSnappedDistance(100, 0); assertSnappedDistance(100, 0);

View File

@ -165,7 +165,7 @@ namespace osu.Game.Tests.Gameplay
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = { BaseDifficulty = { DrainRate = 10 } }, Difficulty = { DrainRate = 10 }
}; };
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 }); beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 });
@ -200,7 +200,7 @@ namespace osu.Game.Tests.Gameplay
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = { BaseDifficulty = { DrainRate = 10 } }, Difficulty = { DrainRate = 10 }
}; };
for (double time = startTime; time <= endTime; time += 100) for (double time = startTime; time <= endTime; time += 100)

View File

@ -182,7 +182,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
var beatmap = createBeatmap(); var beatmap = createBeatmap();
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range }); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; beatmap.Difficulty.SliderMultiplier = 2;
createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true); createTest(beatmap, d => d.RelativeScaleBeatLengthsOverride = true);
AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 5000); AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 5000);
@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
var beatmap = createBeatmap(); var beatmap = createBeatmap();
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range }); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = time_range });
beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2; beatmap.Difficulty.SliderMultiplier = 2;
createTest(beatmap); createTest(beatmap);
AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 2000); AddStep("adjust time range", () => drawableRuleset.TimeRange.Value = 2000);

View File

@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
var beatmap = new Beatmap var beatmap = new Beatmap
{ {
BeatmapInfo = { BaseDifficulty = { ApproachRate = 9 } }, Difficulty = { ApproachRate = 9 },
}; };
for (int i = 0; i < 15; i++) for (int i = 0; i < 15; i++)

View File

@ -7,11 +7,8 @@ using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
@ -29,12 +26,11 @@ using osu.Game.Scoring;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Utils; using osu.Game.Utils;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Navigation namespace osu.Game.Tests.Visual.Navigation
{ {
[TestFixture] [TestFixture]
public class TestSceneOsuGame : OsuTestScene public class TestSceneOsuGame : OsuGameTestScene
{ {
private IReadOnlyList<Type> requiredGameDependencies => new[] private IReadOnlyList<Type> requiredGameDependencies => new[]
{ {
@ -84,34 +80,12 @@ namespace osu.Game.Tests.Visual.Navigation
typeof(PreviewTrackManager), typeof(PreviewTrackManager),
}; };
private OsuGame game;
[Resolved] [Resolved]
private OsuGameBase gameBase { get; set; } private OsuGameBase gameBase { get; set; }
[Resolved] [Resolved]
private GameHost host { get; set; } private GameHost host { get; set; }
[SetUpSteps]
public void SetUpSteps()
{
AddStep("create game", () =>
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
};
AddGame(game = new OsuGame());
});
AddUntilStep("wait for load", () => game.IsLoaded);
}
[Test] [Test]
public void TestNullRulesetHandled() public void TestNullRulesetHandled()
{ {
@ -127,8 +101,8 @@ namespace osu.Game.Tests.Visual.Navigation
[Test] [Test]
public void TestSwitchThreadExecutionMode() public void TestSwitchThreadExecutionMode()
{ {
AddStep("Change thread mode to multi threaded", () => { game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.MultiThreaded); }); AddStep("Change thread mode to multi threaded", () => { Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.MultiThreaded); });
AddStep("Change thread mode to single thread", () => { game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.SingleThread); }); AddStep("Change thread mode to single thread", () => { Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.ExecutionMode, ExecutionMode.SingleThread); });
} }
[Test] [Test]
@ -154,7 +128,7 @@ namespace osu.Game.Tests.Visual.Navigation
{ {
foreach (var type in requiredGameDependencies) foreach (var type in requiredGameDependencies)
{ {
if (game.Dependencies.Get(type) == null) if (Game.Dependencies.Get(type) == null)
throw new InvalidOperationException($"{type} has not been cached"); throw new InvalidOperationException($"{type} has not been cached");
} }

View File

@ -137,11 +137,11 @@ namespace osu.Game.Tests.Visual.Playlists
InputManager.Click(MouseButton.Left); 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()); 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 private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen

View File

@ -18,17 +18,48 @@ namespace osu.Game.Beatmaps
public class Beatmap<T> : IBeatmap<T> public class Beatmap<T> : IBeatmap<T>
where T : HitObject 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", difficulty = value;
Title = @"Unknown",
AuthorString = @"Unknown Creator", if (beatmapInfo != null)
}, beatmapInfo.BaseDifficulty = difficulty.Clone();
Version = @"Normal", }
BaseDifficulty = new BeatmapDifficulty() }
};
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] [JsonIgnore]
public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata; public BeatmapMetadata Metadata => BeatmapInfo?.Metadata ?? BeatmapInfo?.BeatmapSet?.Metadata;

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Database; using osu.Game.Database;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
@ -43,31 +44,31 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public BeatmapDifficulty Clone() public BeatmapDifficulty Clone()
{ {
var diff = new BeatmapDifficulty(); var diff = (BeatmapDifficulty)Activator.CreateInstance(GetType());
CopyTo(diff); CopyTo(diff);
return diff; return diff;
} }
public void CopyFrom(IBeatmapDifficultyInfo difficulty) public virtual void CopyFrom(IBeatmapDifficultyInfo other)
{ {
ApproachRate = difficulty.ApproachRate; ApproachRate = other.ApproachRate;
DrainRate = difficulty.DrainRate; DrainRate = other.DrainRate;
CircleSize = difficulty.CircleSize; CircleSize = other.CircleSize;
OverallDifficulty = difficulty.OverallDifficulty; OverallDifficulty = other.OverallDifficulty;
SliderMultiplier = difficulty.SliderMultiplier; SliderMultiplier = other.SliderMultiplier;
SliderTickRate = difficulty.SliderTickRate; SliderTickRate = other.SliderTickRate;
} }
public void CopyTo(BeatmapDifficulty difficulty) public virtual void CopyTo(BeatmapDifficulty other)
{ {
difficulty.ApproachRate = ApproachRate; other.ApproachRate = ApproachRate;
difficulty.DrainRate = DrainRate; other.DrainRate = DrainRate;
difficulty.CircleSize = CircleSize; other.CircleSize = CircleSize;
difficulty.OverallDifficulty = OverallDifficulty; other.OverallDifficulty = OverallDifficulty;
difficulty.SliderMultiplier = SliderMultiplier; other.SliderMultiplier = SliderMultiplier;
difficulty.SliderTickRate = SliderTickRate; other.SliderTickRate = SliderTickRate;
} }
} }
} }

View File

@ -202,6 +202,8 @@ namespace osu.Game.Beatmaps
using (ContextFactory.GetForWrite()) using (ContextFactory.GetForWrite())
{ {
beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == beatmapInfo.ID); beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == beatmapInfo.ID);
beatmapInfo.BaseDifficulty.CopyFrom(beatmapContent.Difficulty);
var metadata = beatmapInfo.Metadata ?? setInfo.Metadata; var metadata = beatmapInfo.Metadata ?? setInfo.Metadata;
// grab the original file (or create a new one if not found). // grab the original file (or create a new one if not found).

View File

@ -18,7 +18,7 @@ namespace osu.Game.Beatmaps.Formats
stream.ReadToEnd().DeserializeInto(output); stream.ReadToEnd().DeserializeInto(output);
foreach (var hitObject in output.HitObjects) foreach (var hitObject in output.HitObjects)
hitObject.ApplyDefaults(output.ControlPointInfo, output.BeatmapInfo.BaseDifficulty); hitObject.ApplyDefaults(output.ControlPointInfo, output.Difficulty);
} }
} }
} }

View File

@ -67,7 +67,7 @@ namespace osu.Game.Beatmaps.Formats
this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList(); this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList();
foreach (var hitObject in this.beatmap.HitObjects) 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('_'); 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 pair = SplitKeyVal(line);
var difficulty = beatmap.BeatmapInfo.BaseDifficulty; var difficulty = beatmap.Difficulty;
switch (pair.Key) switch (pair.Key)
{ {
@ -444,7 +444,7 @@ namespace osu.Game.Beatmaps.Formats
if (obj != null) if (obj != null)
{ {
obj.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); obj.ApplyDefaults(beatmap.ControlPointInfo, beatmap.Difficulty);
beatmap.HitObjects.Add(obj); beatmap.HitObjects.Add(obj);
} }

View File

@ -141,17 +141,17 @@ namespace osu.Game.Beatmaps.Formats
{ {
writer.WriteLine("[Difficulty]"); writer.WriteLine("[Difficulty]");
writer.WriteLine(FormattableString.Invariant($"HPDrainRate: {beatmap.BeatmapInfo.BaseDifficulty.DrainRate}")); writer.WriteLine(FormattableString.Invariant($"HPDrainRate: {beatmap.Difficulty.DrainRate}"));
writer.WriteLine(FormattableString.Invariant($"CircleSize: {beatmap.BeatmapInfo.BaseDifficulty.CircleSize}")); writer.WriteLine(FormattableString.Invariant($"CircleSize: {beatmap.Difficulty.CircleSize}"));
writer.WriteLine(FormattableString.Invariant($"OverallDifficulty: {beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty}")); writer.WriteLine(FormattableString.Invariant($"OverallDifficulty: {beatmap.Difficulty.OverallDifficulty}"));
writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.BeatmapInfo.BaseDifficulty.ApproachRate}")); writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.Difficulty.ApproachRate}"));
// Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER) // Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER)
writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1 writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1
? FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}") ? FormattableString.Invariant($"SliderMultiplier: {beatmap.Difficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}")
: FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier}")); : 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) private void handleEvents(TextWriter writer)
@ -285,7 +285,7 @@ namespace osu.Game.Beatmaps.Formats
break; break;
case 3: 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)); position.X = (int)Math.Ceiling(((IHasXPosition)hitObject).X * (512f / totalColumns));
break; break;
} }

View File

@ -20,6 +20,11 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
BeatmapMetadata Metadata { get; } BeatmapMetadata Metadata { get; }
/// <summary>
/// This beatmap's difficulty settings.
/// </summary>
public BeatmapDifficulty Difficulty { get; set; }
/// <summary> /// <summary>
/// The control points in this beatmap. /// The control points in this beatmap.
/// </summary> /// </summary>

View File

@ -119,15 +119,12 @@ namespace osu.Game.Beatmaps
// Apply difficulty mods // Apply difficulty mods
if (mods.Any(m => m is IApplicableToDifficulty)) 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<IApplicableToDifficulty>()) foreach (var mod in mods.OfType<IApplicableToDifficulty>())
{ {
if (cancellationSource.IsCancellationRequested) if (cancellationSource.IsCancellationRequested)
throw new BeatmapLoadTimeoutException(BeatmapInfo); throw new BeatmapLoadTimeoutException(BeatmapInfo);
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); mod.ApplyToDifficulty(converted.Difficulty);
} }
} }
@ -146,7 +143,7 @@ namespace osu.Game.Beatmaps
if (cancellationSource.IsCancellationRequested) if (cancellationSource.IsCancellationRequested)
throw new BeatmapLoadTimeoutException(BeatmapInfo); throw new BeatmapLoadTimeoutException(BeatmapInfo);
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty, cancellationSource.Token); obj.ApplyDefaults(converted.ControlPointInfo, converted.Difficulty, cancellationSource.Token);
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)

View File

@ -258,6 +258,13 @@ namespace osu.Game.Rulesets.Difficulty
} }
public BeatmapMetadata Metadata => baseBeatmap.Metadata; public BeatmapMetadata Metadata => baseBeatmap.Metadata;
public BeatmapDifficulty Difficulty
{
get => baseBeatmap.Difficulty;
set => baseBeatmap.Difficulty = value;
}
public List<BreakPeriod> Breaks => baseBeatmap.Breaks; public List<BreakPeriod> Breaks => baseBeatmap.Breaks;
public double TotalBreakTime => baseBeatmap.TotalBreakTime; public double TotalBreakTime => baseBeatmap.TotalBreakTime;
public IEnumerable<BeatmapStatistic> GetStatistics() => baseBeatmap.GetStatistics(); public IEnumerable<BeatmapStatistic> GetStatistics() => baseBeatmap.GetStatistics();

View File

@ -392,7 +392,7 @@ namespace osu.Game.Rulesets.Edit
public override float GetBeatSnapDistanceAt(double referenceTime) public override float GetBeatSnapDistanceAt(double referenceTime)
{ {
DifficultyControlPoint difficultyPoint = EditorBeatmap.ControlPointInfo.DifficultyPointAt(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) public override float DurationToDistance(double referenceTime, double duration)

View File

@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Edit
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,IBeatmapDifficultyInfo,CancellationToken)"/>, /// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,IBeatmapDifficultyInfo,CancellationToken)"/>,
/// refreshing <see cref="Objects.HitObject.NestedHitObjects"/> and parameters for the <see cref="HitObject"/>. /// refreshing <see cref="Objects.HitObject.NestedHitObjects"/> and parameters for the <see cref="HitObject"/>.
/// </summary> /// </summary>
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; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent?.ReceivePositionalInputAt(screenSpacePos) ?? false;

View File

@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mods
/// <summary> /// <summary>
/// A function that can extract the current value of this setting from a beatmap difficulty for display purposes. /// A function that can extract the current value of this setting from a beatmap difficulty for display purposes.
/// </summary> /// </summary>
public Func<BeatmapDifficulty, float> ReadCurrentFromDifficulty; public Func<IBeatmapDifficultyInfo, float> ReadCurrentFromDifficulty;
public float Precision public float Precision
{ {

View File

@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Scoring
.First() .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. // Add back a portion of the amount of HP to be drained, depending on the lenience requested.
targetMinimumHealth += drainLenience * (1 - targetMinimumHealth); targetMinimumHealth += drainLenience * (1 - targetMinimumHealth);

View File

@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
maxDuration = duration; maxDuration = duration;
// The slider multiplier is post-multiplied to determine the final velocity, but for relative scale beat lengths // 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 // 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) return new MultiplierControlPoint(c.Time)
{ {
Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier, Velocity = Beatmap.Difficulty.SliderMultiplier,
BaseBeatLength = baseBeatLength, BaseBeatLength = baseBeatLength,
TimingPoint = lastTimingPoint, TimingPoint = lastTimingPoint,
DifficultyPoint = lastDifficultyPoint DifficultyPoint = lastDifficultyPoint
@ -172,7 +172,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
ControlPoints.AddRange(timingChanges); ControlPoints.AddRange(timingChanges);
if (ControlPoints.Count == 0) 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() protected override void LoadComplete()

View File

@ -86,6 +86,12 @@ namespace osu.Game.Screens.Edit
public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; public BeatmapMetadata Metadata => PlayableBeatmap.Metadata;
public BeatmapDifficulty Difficulty
{
get => PlayableBeatmap.Difficulty;
set => PlayableBeatmap.Difficulty = value;
}
public ControlPointInfo ControlPointInfo public ControlPointInfo ControlPointInfo
{ {
get => PlayableBeatmap.ControlPointInfo; get => PlayableBeatmap.ControlPointInfo;
@ -286,7 +292,7 @@ namespace osu.Game.Screens.Edit
/// </summary> /// </summary>
public void Clear() => RemoveRange(HitObjects.ToArray()); 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) private void trackStartTime(HitObject hitObject)
{ {

View File

@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Setup
Label = "Object Size", Label = "Object Size",
FixedLabelWidth = LABEL_WIDTH, FixedLabelWidth = LABEL_WIDTH,
Description = "The size of all hit objects", Description = "The size of all hit objects",
Current = new BindableFloat(Beatmap.BeatmapInfo.BaseDifficulty.CircleSize) Current = new BindableFloat(Beatmap.Difficulty.CircleSize)
{ {
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
MinValue = 0, MinValue = 0,
@ -43,7 +43,7 @@ namespace osu.Game.Screens.Edit.Setup
Label = "Health Drain", Label = "Health Drain",
FixedLabelWidth = LABEL_WIDTH, FixedLabelWidth = LABEL_WIDTH,
Description = "The rate of passive health drain throughout playable time", 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, Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
MinValue = 0, MinValue = 0,
@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit.Setup
Label = "Approach Rate", Label = "Approach Rate",
FixedLabelWidth = LABEL_WIDTH, FixedLabelWidth = LABEL_WIDTH,
Description = "The speed at which objects are presented to the player", 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, Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
MinValue = 0, MinValue = 0,
@ -69,7 +69,7 @@ namespace osu.Game.Screens.Edit.Setup
Label = "Overall Difficulty", Label = "Overall Difficulty",
FixedLabelWidth = LABEL_WIDTH, FixedLabelWidth = LABEL_WIDTH,
Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)", 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, Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
MinValue = 0, MinValue = 0,
@ -87,10 +87,10 @@ namespace osu.Game.Screens.Edit.Setup
{ {
// for now, update these on commit rather than making BeatmapMetadata bindables. // 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. // after switching database engines we can reconsider if switching to bindables is a good direction.
Beatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value; Beatmap.Difficulty.CircleSize = circleSizeSlider.Current.Value;
Beatmap.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value; Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value; Beatmap.Difficulty.ApproachRate = approachRateSlider.Current.Value;
Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value; Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
Beatmap.UpdateAllHitObjects(); Beatmap.UpdateAllHitObjects();
} }

View File

@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; 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()))); 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) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs(new EditorClock()); dependencies.CacheAs(new EditorClock());
var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); var playable = GetPlayableBeatmap();
dependencies.CacheAs(new EditorBeatmap(playable)); dependencies.CacheAs(new EditorBeatmap(playable));
return dependencies; 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() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();