mirror of
https://github.com/ppy/osu
synced 2024-12-14 19:06:07 +00:00
Merge branch 'master' of https://github.com/ppy/osu
This commit is contained in:
commit
c44d07e9c6
@ -36,18 +36,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
new Speed()
|
||||
};
|
||||
|
||||
double sectionEnd = section_length / TimeRate;
|
||||
double sectionLength = section_length * TimeRate;
|
||||
|
||||
// The first object doesn't generate a strain, so we begin with an incremented section end
|
||||
double currentSectionEnd = 2 * sectionLength;
|
||||
|
||||
foreach (OsuDifficultyHitObject h in beatmap)
|
||||
{
|
||||
while (h.BaseObject.StartTime > sectionEnd)
|
||||
while (h.BaseObject.StartTime > currentSectionEnd)
|
||||
{
|
||||
foreach (Skill s in skills)
|
||||
{
|
||||
s.SaveCurrentPeak();
|
||||
s.StartNewSectionFrom(sectionEnd);
|
||||
s.StartNewSectionFrom(currentSectionEnd);
|
||||
}
|
||||
|
||||
sectionEnd += section_length;
|
||||
currentSectionEnd += sectionLength;
|
||||
}
|
||||
|
||||
foreach (Skill s in skills)
|
||||
|
@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
public class OsuDifficultyBeatmap : IEnumerable<OsuDifficultyHitObject>
|
||||
{
|
||||
private readonly IEnumerator<OsuDifficultyHitObject> difficultyObjects;
|
||||
private readonly Queue<OsuDifficultyHitObject> onScreen = new Queue<OsuDifficultyHitObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an enumerator, which preprocesses a list of <see cref="OsuHitObject"/>s recieved as input, wrapping them as
|
||||
@ -30,65 +29,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that enumerates all <see cref="OsuDifficultyHitObject"/>s in the <see cref="OsuDifficultyBeatmap"/>.
|
||||
/// The inner loop adds objects that appear on screen into a queue until we need to hit the next object.
|
||||
/// The outer loop returns objects from this queue one at a time, only after they had to be hit, and should no longer be on screen.
|
||||
/// This means that we can loop through every object that is on screen at the time when a new one appears,
|
||||
/// allowing us to determine a reading strain for the object that just appeared.
|
||||
/// </summary>
|
||||
public IEnumerator<OsuDifficultyHitObject> GetEnumerator()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Add upcoming objects to the queue until we have at least one object that had been hit and can be dequeued.
|
||||
// This means there is always at least one object in the queue unless we reached the end of the map.
|
||||
do
|
||||
{
|
||||
if (!difficultyObjects.MoveNext())
|
||||
break; // New objects can't be added anymore, but we still need to dequeue and return the ones already on screen.
|
||||
|
||||
OsuDifficultyHitObject latest = difficultyObjects.Current;
|
||||
// Calculate flow values here
|
||||
|
||||
foreach (OsuDifficultyHitObject h in onScreen)
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException (resharper not smart enough to understand IEnumerator.MoveNext())
|
||||
h.TimeUntilHit -= latest.DeltaTime;
|
||||
// Calculate reading strain here
|
||||
}
|
||||
|
||||
onScreen.Enqueue(latest);
|
||||
}
|
||||
while (onScreen.Peek().TimeUntilHit > 0); // Keep adding new objects on screen while there is still time before we have to hit the next one.
|
||||
|
||||
if (onScreen.Count == 0) break; // We have reached the end of the map and enumerated all the objects.
|
||||
yield return onScreen.Dequeue(); // Remove and return objects one by one that had to be hit before the latest one appeared.
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<OsuDifficultyHitObject> GetEnumerator() => difficultyObjects;
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
private IEnumerator<OsuDifficultyHitObject> createDifficultyObjectEnumerator(List<OsuHitObject> objects, double timeRate)
|
||||
{
|
||||
// We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object.
|
||||
OsuHitObject[] triangle = new OsuHitObject[3];
|
||||
|
||||
// OsuDifficultyHitObject construction requires three components, an extra copy of the first OsuHitObject is used at the beginning.
|
||||
if (objects.Count > 1)
|
||||
{
|
||||
triangle[1] = objects[0]; // This copy will get shifted to the last spot in the triangle.
|
||||
triangle[0] = objects[0]; // This component corresponds to the real first OsuHitOject.
|
||||
}
|
||||
|
||||
// The final component of the first triangle will be the second OsuHitOject of the map, which forms the first jump.
|
||||
// The first jump is formed by the first two hitobjects of the map.
|
||||
// If the map has less than two OsuHitObjects, the enumerator will not return anything.
|
||||
for (int i = 1; i < objects.Count; ++i)
|
||||
{
|
||||
triangle[2] = triangle[1];
|
||||
triangle[1] = triangle[0];
|
||||
triangle[0] = objects[i];
|
||||
|
||||
yield return new OsuDifficultyHitObject(triangle, timeRate);
|
||||
}
|
||||
for (int i = 1; i < objects.Count; i++)
|
||||
yield return new OsuDifficultyHitObject(objects[i], objects[i - 1], timeRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
/// </summary>
|
||||
public class OsuDifficultyHitObject
|
||||
{
|
||||
private const int normalized_radius = 52;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="OsuHitObject"/> this <see cref="OsuDifficultyHitObject"/> refers to.
|
||||
/// </summary>
|
||||
@ -28,26 +30,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
/// </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 OsuHitObject lastObject;
|
||||
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)
|
||||
public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate)
|
||||
{
|
||||
this.lastObject = lastObject;
|
||||
this.timeRate = timeRate;
|
||||
|
||||
t = triangle;
|
||||
BaseObject = t[0];
|
||||
BaseObject = currentObject;
|
||||
|
||||
setDistances();
|
||||
setTimingValues();
|
||||
// Calculate angle here
|
||||
@ -63,10 +58,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
scalingFactor *= 1 + smallCircleBonus;
|
||||
}
|
||||
|
||||
Vector2 lastCursorPosition = t[1].StackedPosition;
|
||||
Vector2 lastCursorPosition = lastObject.StackedPosition;
|
||||
float lastTravelDistance = 0;
|
||||
|
||||
var lastSlider = t[1] as Slider;
|
||||
var lastSlider = lastObject as Slider;
|
||||
if (lastSlider != null)
|
||||
{
|
||||
computeSliderCursorPosition(lastSlider);
|
||||
@ -80,8 +75,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
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;
|
||||
DeltaTime = Math.Max(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate);
|
||||
}
|
||||
|
||||
private void computeSliderCursorPosition(Slider slider)
|
||||
@ -107,7 +101,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
}
|
||||
});
|
||||
|
||||
var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime);
|
||||
// Skip the head circle
|
||||
var scoringTimes = slider.NestedHitObjects.Skip(1).Select(t => t.StartTime);
|
||||
foreach (var time in scoringTimes)
|
||||
computeVertex(time);
|
||||
computeVertex(slider.EndTime);
|
||||
|
@ -19,10 +19,10 @@ namespace osu.Game.Rulesets.Mods
|
||||
public void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
||||
{
|
||||
const float ratio = 1.4f;
|
||||
difficulty.CircleSize *= 1.3f; // CS uses a custom 1.3 ratio.
|
||||
difficulty.CircleSize = Math.Min(difficulty.CircleSize * 1.3f, 10.0f); // CS uses a custom 1.3 ratio.
|
||||
difficulty.ApproachRate = Math.Min(difficulty.ApproachRate * ratio, 10.0f);
|
||||
difficulty.DrainRate *= ratio;
|
||||
difficulty.OverallDifficulty *= ratio;
|
||||
difficulty.DrainRate = Math.Min(difficulty.DrainRate * ratio, 10.0f);
|
||||
difficulty.OverallDifficulty = Math.Min(difficulty.OverallDifficulty * ratio, 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user