mirror of
https://github.com/ppy/osu.git
synced 2024-11-18 07:32:54 +08:00
b04e2cbb5c
The main bug was that the beatmap was not being processed prior to having its Skill values calculated, causing stacking to be ignored in difficulty calculation. The fix involves processing the beatmap with OsuBeatmapProcessor. Another minor bug was that sliders were not taking into account the stacked position midway through the slider (PositionAt does not return stacked position.), so I corrected by adding StackOffset.
118 lines
4.5 KiB
C#
118 lines
4.5 KiB
C#
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using osu.Game.Rulesets.Objects.Types;
|
|
using OpenTK;
|
|
using osu.Game.Rulesets.Osu.Objects;
|
|
|
|
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|
{
|
|
/// <summary>
|
|
/// A wrapper around <see cref="OsuHitObject"/> extending it with additional data required for difficulty calculation.
|
|
/// </summary>
|
|
public class OsuDifficultyHitObject
|
|
{
|
|
/// <summary>
|
|
/// The <see cref="OsuHitObject"/> this <see cref="OsuDifficultyHitObject"/> refers to.
|
|
/// </summary>
|
|
public OsuHitObject BaseObject { get; }
|
|
|
|
/// <summary>
|
|
/// Normalized distance from the <see cref="OsuHitObject.StackedPosition"/> of the previous <see cref="OsuDifficultyHitObject"/>.
|
|
/// </summary>
|
|
public double Distance { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Milliseconds elapsed since the StartTime of the previous <see cref="OsuDifficultyHitObject"/>.
|
|
/// </summary>
|
|
public double DeltaTime { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Number of milliseconds until the <see cref="OsuDifficultyHitObject"/> has to be hit.
|
|
/// </summary>
|
|
public double TimeUntilHit { get; set; }
|
|
|
|
private const int normalized_radius = 52;
|
|
|
|
private readonly double timeRate;
|
|
|
|
private readonly OsuHitObject[] t;
|
|
|
|
/// <summary>
|
|
/// Initializes the object calculating extra data required for difficulty calculation.
|
|
/// </summary>
|
|
public OsuDifficultyHitObject(OsuHitObject[] triangle, double timeRate)
|
|
{
|
|
this.timeRate = timeRate;
|
|
|
|
t = triangle;
|
|
BaseObject = t[0];
|
|
setDistances();
|
|
setTimingValues();
|
|
// Calculate angle here
|
|
}
|
|
|
|
private void setDistances()
|
|
{
|
|
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
|
double scalingFactor = normalized_radius / BaseObject.Radius;
|
|
if (BaseObject.Radius < 30)
|
|
{
|
|
double smallCircleBonus = Math.Min(30 - BaseObject.Radius, 5) / 50;
|
|
scalingFactor *= 1 + smallCircleBonus;
|
|
}
|
|
|
|
Vector2 lastCursorPosition = t[1].StackedPosition;
|
|
float lastTravelDistance = 0;
|
|
|
|
var lastSlider = t[1] as Slider;
|
|
if (lastSlider != null)
|
|
{
|
|
computeSliderCursorPosition(lastSlider);
|
|
lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition;
|
|
lastTravelDistance = lastSlider.LazyTravelDistance;
|
|
}
|
|
|
|
Distance = (lastTravelDistance + (BaseObject.StackedPosition - lastCursorPosition).Length) * scalingFactor;
|
|
}
|
|
|
|
private void setTimingValues()
|
|
{
|
|
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
|
DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate);
|
|
TimeUntilHit = 450; // BaseObject.PreEmpt;
|
|
}
|
|
|
|
private void computeSliderCursorPosition(Slider slider)
|
|
{
|
|
if (slider.LazyEndPosition != null)
|
|
return;
|
|
slider.LazyEndPosition = slider.StackedPosition;
|
|
|
|
float approxFollowCircleRadius = (float)(slider.Radius * 3);
|
|
var computeVertex = new Action<double>(t =>
|
|
{
|
|
// ReSharper disable once PossibleInvalidOperationException (bugged in current r# version)
|
|
var diff = slider.PositionAt(t) + slider.StackOffset - slider.LazyEndPosition.Value;
|
|
float dist = diff.Length;
|
|
|
|
if (dist > approxFollowCircleRadius)
|
|
{
|
|
// The cursor would be outside the follow circle, we need to move it
|
|
diff.Normalize(); // Obtain direction of diff
|
|
dist -= approxFollowCircleRadius;
|
|
slider.LazyEndPosition += diff * dist;
|
|
slider.LazyTravelDistance += dist;
|
|
}
|
|
});
|
|
|
|
var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime);
|
|
foreach (var time in scoringTimes)
|
|
computeVertex(time);
|
|
computeVertex(slider.EndTime);
|
|
}
|
|
}
|
|
}
|