1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-23 02:39:52 +08:00
Files
osu-lazer/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs
T
Nathan Corbett b0047e4570 Use variable-length strains to fix chunking-related issues (#33351)
- Closes https://github.com/ppy/osu/issues/25254

Solves chunking-related issues by starting a new chunk for every object,
and allowing chunks to be different lengths. This is retrofitted to
existing calculations, and doesn't have other ramifications in the way
something like tr3s's continuous strains do.

The effect of this can be seen in the video below. In live pp, the map
would lose sr when increasing the rate at certain points, but in the
video, the sr rises consistently as expected.


https://github.com/user-attachments/assets/2d58946a-9e0c-4f6b-912a-71dfe75c0f8a

A multiplier has been added inside `DifficultyValue()` to account for SR
being slightly lower from more granular summation.

When testing this rework in PerformanceCalculatorGUI, I recommend using
[this
fork](https://github.com/Finadoggie/osu-tools/tree/variable-length-strains).
I can't guarantee that the visuals it shows are correct, but they are
definitely more correct than not.

Edit: Use [this
fork](https://github.com/Finadoggie/osu-tools/tree/unsynced-variable-length-strains)
for testing now. Old one is now for testing
SynchronizedVariableLengthStrainSkill

---------

Co-authored-by: tsunyoku <tsunyoku@gmail.com>
Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com>
2026-03-27 20:08:20 +00:00

65 lines
2.3 KiB
C#

// 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.
#nullable disable
using System.IO;
using System.Reflection;
using NUnit.Framework;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Tests.Beatmaps
{
[TestFixture]
public abstract class DifficultyCalculatorTest
{
private const string resource_namespace = "Testing.Beatmaps";
protected abstract string ResourceAssembly { get; }
protected void Test(double? expectedStarRating, int expectedMaxCombo, string name, params Mod[] mods)
{
var attributes = CreateDifficultyCalculator(GetBeatmap(name)).Calculate(mods);
// Platform-dependent math functions (Pow, Cbrt, Exp, etc) may result in minute differences.
Assert.That(attributes.StarRating, Is.EqualTo(expectedStarRating).Within(0.00001));
Assert.That(attributes.MaxCombo, Is.EqualTo(expectedMaxCombo));
}
protected IWorkingBeatmap GetBeatmap(string name)
{
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
using (var stream = new LineBufferedReader(resStream))
{
var decoder = Decoder.GetDecoder<Beatmap>(stream);
((LegacyBeatmapDecoder)decoder).ApplyOffsets = false;
return new TestWorkingBeatmap(decoder.Decode(stream))
{
BeatmapInfo =
{
Ruleset = CreateRuleset().RulesetInfo
}
};
}
}
private Stream openResource(string name)
{
string localPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location).AsNonNull();
return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
}
protected abstract DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap);
protected abstract Ruleset CreateRuleset();
}
}