mirror of
https://github.com/osukey/osukey.git
synced 2025-08-08 09:03:50 +09:00
Merge branch 'master' into fix-quick-retry-music-playback
This commit is contained in:
@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new CatchPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public int LegacyID => 2;
|
public int LegacyID => 2;
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -25,8 +24,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
private int tinyTicksMissed;
|
private int tinyTicksMissed;
|
||||||
private int misses;
|
private int misses;
|
||||||
|
|
||||||
public CatchPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public CatchPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -29,8 +28,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public ManiaPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new ManiaPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public const string SHORT_NAME = "mania";
|
public const string SHORT_NAME = "mania";
|
||||||
|
|
||||||
|
@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
public double SpeedStrain;
|
public double SpeedStrain;
|
||||||
public double ApproachRate;
|
public double ApproachRate;
|
||||||
public double OverallDifficulty;
|
public double OverallDifficulty;
|
||||||
|
public int HitCircleCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
// 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)
|
||||||
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
|
|
||||||
|
int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
return new OsuDifficultyAttributes
|
return new OsuDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
@ -56,6 +58,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||||
MaxCombo = maxCombo,
|
MaxCombo = maxCombo,
|
||||||
|
HitCircleCount = hitCirclesCount,
|
||||||
Skills = skills
|
Skills = skills
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,9 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -19,9 +17,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
|
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
|
||||||
|
|
||||||
private readonly int countHitCircles;
|
|
||||||
private readonly int beatmapMaxCombo;
|
|
||||||
|
|
||||||
private Mod[] mods;
|
private Mod[] mods;
|
||||||
|
|
||||||
private double accuracy;
|
private double accuracy;
|
||||||
@ -31,14 +26,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public OsuPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
|
||||||
|
|
||||||
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
|
||||||
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
|
||||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
||||||
@ -81,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
categoryRatings.Add("Accuracy", accuracyValue);
|
categoryRatings.Add("Accuracy", accuracyValue);
|
||||||
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
||||||
categoryRatings.Add("AR", Attributes.ApproachRate);
|
categoryRatings.Add("AR", Attributes.ApproachRate);
|
||||||
categoryRatings.Add("Max Combo", beatmapMaxCombo);
|
categoryRatings.Add("Max Combo", Attributes.MaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
@ -106,8 +96,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimValue *= Math.Pow(0.97, countMiss);
|
aimValue *= Math.Pow(0.97, countMiss);
|
||||||
|
|
||||||
// Combo scaling
|
// Combo scaling
|
||||||
if (beatmapMaxCombo > 0)
|
if (Attributes.MaxCombo > 0)
|
||||||
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(beatmapMaxCombo, 0.8), 1.0);
|
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
double approachRateFactor = 1.0;
|
double approachRateFactor = 1.0;
|
||||||
|
|
||||||
@ -154,8 +144,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
speedValue *= Math.Pow(0.97, countMiss);
|
speedValue *= Math.Pow(0.97, countMiss);
|
||||||
|
|
||||||
// Combo scaling
|
// Combo scaling
|
||||||
if (beatmapMaxCombo > 0)
|
if (Attributes.MaxCombo > 0)
|
||||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(beatmapMaxCombo, 0.8), 1.0);
|
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
double approachRateFactor = 1.0;
|
double approachRateFactor = 1.0;
|
||||||
if (Attributes.ApproachRate > 10.33)
|
if (Attributes.ApproachRate > 10.33)
|
||||||
@ -178,7 +168,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
||||||
double betterAccuracyPercentage;
|
double betterAccuracyPercentage;
|
||||||
int amountHitObjectsWithAccuracy = countHitCircles;
|
int amountHitObjectsWithAccuracy = Attributes.HitCircleCount;
|
||||||
|
|
||||||
if (amountHitObjectsWithAccuracy > 0)
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
||||||
|
@ -171,7 +171,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new OsuPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new OsuPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -24,8 +23,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public TaikoPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -14,13 +15,29 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
{
|
{
|
||||||
public class TaikoLegacySkinTransformer : LegacySkinTransformer
|
public class TaikoLegacySkinTransformer : LegacySkinTransformer
|
||||||
{
|
{
|
||||||
|
private Lazy<bool> hasExplosion;
|
||||||
|
|
||||||
public TaikoLegacySkinTransformer(ISkinSource source)
|
public TaikoLegacySkinTransformer(ISkinSource source)
|
||||||
: base(source)
|
: base(source)
|
||||||
{
|
{
|
||||||
|
Source.SourceChanged += sourceChanged;
|
||||||
|
sourceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sourceChanged()
|
||||||
|
{
|
||||||
|
hasExplosion = new Lazy<bool>(() => Source.GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Drawable GetDrawableComponent(ISkinComponent component)
|
public override Drawable GetDrawableComponent(ISkinComponent component)
|
||||||
{
|
{
|
||||||
|
if (component is GameplaySkinComponent<HitResult>)
|
||||||
|
{
|
||||||
|
// if a taiko skin is providing explosion sprites, hide the judgements completely
|
||||||
|
if (hasExplosion.Value)
|
||||||
|
return Drawable.Empty();
|
||||||
|
}
|
||||||
|
|
||||||
if (!(component is TaikoSkinComponent taikoComponent))
|
if (!(component is TaikoSkinComponent taikoComponent))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -87,10 +104,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
var hitName = getHitName(taikoComponent.Component);
|
var hitName = getHitName(taikoComponent.Component);
|
||||||
var hitSprite = this.GetAnimation(hitName, true, false);
|
var hitSprite = this.GetAnimation(hitName, true, false);
|
||||||
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
|
||||||
|
|
||||||
if (hitSprite != null)
|
if (hitSprite != null)
|
||||||
|
{
|
||||||
|
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
||||||
|
|
||||||
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new TaikoPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new TaikoPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public int LegacyID => 1;
|
public int LegacyID => 1;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 }
|
new HitCircle { StartTime = 1000, NewCombo = true }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -100,7 +100,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -109,7 +109,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
(OsuHitObject)current.HitObjects[1],
|
(OsuHitObject)current.HitObjects[1],
|
||||||
(OsuHitObject)current.HitObjects[2],
|
(OsuHitObject)current.HitObjects[2],
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -146,7 +146,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new OsuHitObject[]
|
current.AddRange(new OsuHitObject[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new Slider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = 2000,
|
StartTime = 2000,
|
||||||
@ -188,7 +188,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -197,7 +197,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
(OsuHitObject)current.HitObjects[0],
|
(OsuHitObject)current.HitObjects[0],
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
(OsuHitObject)current.HitObjects[1],
|
(OsuHitObject)current.HitObjects[1],
|
||||||
@ -216,7 +216,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000 },
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
@ -226,6 +226,9 @@ namespace osu.Game.Tests.Editing
|
|||||||
new HitCircle { StartTime = 3500 },
|
new HitCircle { StartTime = 3500 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var patchedFirst = (HitCircle)current.HitObjects[1];
|
||||||
|
patchedFirst.NewCombo = true;
|
||||||
|
|
||||||
var patch = new OsuBeatmap
|
var patch = new OsuBeatmap
|
||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
@ -244,7 +247,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000 },
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
@ -277,7 +280,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000 },
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
@ -291,7 +294,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 750 },
|
new HitCircle { StartTime = 750, NewCombo = true },
|
||||||
(OsuHitObject)current.HitObjects[1],
|
(OsuHitObject)current.HitObjects[1],
|
||||||
(OsuHitObject)current.HitObjects[4],
|
(OsuHitObject)current.HitObjects[4],
|
||||||
(OsuHitObject)current.HitObjects[5],
|
(OsuHitObject)current.HitObjects[5],
|
||||||
@ -309,20 +312,20 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(50) },
|
new HitCircle { StartTime = 500, Position = new Vector2(50), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(100) },
|
new HitCircle { StartTime = 500, Position = new Vector2(100), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(150) },
|
new HitCircle { StartTime = 500, Position = new Vector2(150), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(200) },
|
new HitCircle { StartTime = 500, Position = new Vector2(200), NewCombo = true },
|
||||||
});
|
});
|
||||||
|
|
||||||
var patch = new OsuBeatmap
|
var patch = new OsuBeatmap
|
||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(150) },
|
new HitCircle { StartTime = 500, Position = new Vector2(150), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(100) },
|
new HitCircle { StartTime = 500, Position = new Vector2(100), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(50) },
|
new HitCircle { StartTime = 500, Position = new Vector2(50), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(200) },
|
new HitCircle { StartTime = 500, Position = new Vector2(200), NewCombo = true },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,8 +22,18 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
IHasComboInformation lastObj = null;
|
IHasComboInformation lastObj = null;
|
||||||
|
|
||||||
|
bool isFirst = true;
|
||||||
|
|
||||||
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
||||||
{
|
{
|
||||||
|
if (isFirst)
|
||||||
|
{
|
||||||
|
obj.NewCombo = true;
|
||||||
|
|
||||||
|
// first hitobject should always be marked as a new combo for sanity.
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (obj.NewCombo)
|
if (obj.NewCombo)
|
||||||
{
|
{
|
||||||
obj.IndexInCurrentCombo = 0;
|
obj.IndexInCurrentCombo = 0;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// 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 System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -16,19 +16,16 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
protected readonly DifficultyAttributes Attributes;
|
protected readonly DifficultyAttributes Attributes;
|
||||||
|
|
||||||
protected readonly Ruleset Ruleset;
|
protected readonly Ruleset Ruleset;
|
||||||
protected readonly IBeatmap Beatmap;
|
|
||||||
protected readonly ScoreInfo Score;
|
protected readonly ScoreInfo Score;
|
||||||
|
|
||||||
protected double TimeRate { get; private set; } = 1;
|
protected double TimeRate { get; private set; } = 1;
|
||||||
|
|
||||||
protected PerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
protected PerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
{
|
{
|
||||||
Ruleset = ruleset;
|
Ruleset = ruleset;
|
||||||
Score = score;
|
Score = score;
|
||||||
|
|
||||||
Beatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods);
|
Attributes = attributes ?? throw new ArgumentNullException(nameof(attributes));
|
||||||
|
|
||||||
Attributes = ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods);
|
|
||||||
|
|
||||||
ApplyMods(score.Mods);
|
ApplyMods(score.Mods);
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
// apply any custom state overrides
|
// apply any custom state overrides
|
||||||
ApplyCustomUpdateState?.Invoke(this, newState);
|
ApplyCustomUpdateState?.Invoke(this, newState);
|
||||||
|
|
||||||
if (newState == ArmedState.Hit)
|
if (!force && newState == ArmedState.Hit)
|
||||||
PlaySamples();
|
PlaySamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,28 @@ namespace osu.Game.Rulesets
|
|||||||
|
|
||||||
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
||||||
|
|
||||||
public virtual PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => null;
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="PerformanceCalculator"/> to generate performance data from the provided score.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attributes">Difficulty attributes for the beatmap related to the provided score.</param>
|
||||||
|
/// <param name="score">The score to be processed.</param>
|
||||||
|
/// <returns>A performance calculator instance for the provided score.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public virtual PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="PerformanceCalculator"/> to generate performance data from the provided score.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to use as a source for generating <see cref="DifficultyAttributes"/>.</param>
|
||||||
|
/// <param name="score">The score to be processed.</param>
|
||||||
|
/// <returns>A performance calculator instance for the provided score.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score)
|
||||||
|
{
|
||||||
|
var difficultyCalculator = CreateDifficultyCalculator(beatmap);
|
||||||
|
var difficultyAttributes = difficultyCalculator.Calculate(score.Mods);
|
||||||
|
return CreatePerformanceCalculator(difficultyAttributes, score);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual HitObjectComposer CreateHitObjectComposer() => null;
|
public virtual HitObjectComposer CreateHitObjectComposer() => null;
|
||||||
|
|
||||||
|
@ -315,5 +315,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
public double GetBeatLengthAtTime(double referenceTime) => ControlPointInfo.TimingPointAt(referenceTime).BeatLength / BeatDivisor;
|
public double GetBeatLengthAtTime(double referenceTime) => ControlPointInfo.TimingPointAt(referenceTime).BeatLength / BeatDivisor;
|
||||||
|
|
||||||
public int BeatDivisor => beatDivisor?.Value ?? 1;
|
public int BeatDivisor => beatDivisor?.Value ?? 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update all hit objects with potentially changed difficulty or control point data.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateBeatmap()
|
||||||
|
{
|
||||||
|
foreach (var h in HitObjects)
|
||||||
|
pendingUpdates.Add(h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
99
osu.Game/Screens/Edit/Setup/DifficultySection.cs
Normal file
99
osu.Game/Screens/Edit/Setup/DifficultySection.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
|
{
|
||||||
|
internal class DifficultySection : SetupSection
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private EditorBeatmap editorBeatmap { get; set; }
|
||||||
|
|
||||||
|
private LabelledSliderBar<float> circleSizeSlider;
|
||||||
|
private LabelledSliderBar<float> healthDrainSlider;
|
||||||
|
private LabelledSliderBar<float> approachRateSlider;
|
||||||
|
private LabelledSliderBar<float> overallDifficultySlider;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Difficulty settings"
|
||||||
|
},
|
||||||
|
circleSizeSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Object Size",
|
||||||
|
Description = "The size of all hit objects",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 2,
|
||||||
|
MaxValue = 7,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
healthDrainSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Health Drain",
|
||||||
|
Description = "The rate of passive health drain throughout playable time",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
approachRateSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Approach Rate",
|
||||||
|
Description = "The speed at which objects are presented to the player",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
overallDifficultySlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Overall Difficulty",
|
||||||
|
Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var item in Children.OfType<LabelledSliderBar<float>>())
|
||||||
|
item.Current.ValueChanged += onValueChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onValueChanged(ValueChangedEvent<float> args)
|
||||||
|
{
|
||||||
|
// 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.Value.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
|
||||||
|
|
||||||
|
editorBeatmap.UpdateBeatmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,7 @@ namespace osu.Game.Screens.Edit.Setup
|
|||||||
{
|
{
|
||||||
new ResourcesSection(),
|
new ResourcesSection(),
|
||||||
new MetadataSection(),
|
new MetadataSection(),
|
||||||
|
new DifficultySection(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user