Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use osu!stable hitwindows for converted hitobjects #2524

Merged
merged 13 commits into from May 15, 2018
@@ -59,7 +59,6 @@ public ManiaBeatmapConverter(IBeatmap beatmap)

protected override Beatmap<ManiaHitObject> ConvertBeatmap(IBeatmap original)
{

BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;

int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate);
@@ -85,7 +84,10 @@ protected override IEnumerable<ManiaHitObject> ConvertHitObject(HitObject origin
yield break;

foreach (ManiaHitObject obj in objects)
{
obj.HitWindows = original.HitWindows;
yield return obj;
}
}

private readonly List<double> prevNoteTimes = new List<double>(max_notes_for_density);
@@ -103,6 +103,7 @@ private class TailNote : Note
/// <summary>
/// Lenience of release hit windows. This is to make cases where the hold note release
/// is timed alongside presses of other hit objects less awkward.
/// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps
/// </summary>
private const double release_window_lenience = 1.5;

@@ -40,7 +40,8 @@ protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original
RepeatSamples = curveData.RepeatSamples,
RepeatCount = curveData.RepeatCount,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
NewCombo = comboData?.NewCombo ?? false,
HitWindows = original.HitWindows
};
}
else if (endTimeData != null)
@@ -50,8 +51,8 @@ protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original
StartTime = original.StartTime,
Samples = original.Samples,
EndTime = endTimeData.EndTime,

Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
HitWindows = original.HitWindows
};
}
else
@@ -61,7 +62,8 @@ protected override IEnumerable<OsuHitObject> ConvertHitObject(HitObject original
StartTime = original.StartTime,
Samples = original.Samples,
Position = positionData?.Position ?? Vector2.Zero,
NewCombo = comboData?.NewCombo ?? false
NewCombo = comboData?.NewCombo ?? false,
HitWindows = original.HitWindows
};
}
}
@@ -132,7 +132,8 @@ protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, I
{
StartTime = j,
Samples = currentSamples,
IsStrong = strong
IsStrong = strong,
HitWindows = obj.HitWindows
};
}
else
@@ -142,6 +143,7 @@ protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, I
StartTime = j,
Samples = currentSamples,
IsStrong = strong,
HitWindows = obj.HitWindows
};
}

@@ -157,6 +159,7 @@ protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, I
IsStrong = strong,
Duration = taikoDuration,
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4,
HitWindows = obj.HitWindows
};
}
}
@@ -171,6 +174,7 @@ protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, I
IsStrong = strong,
Duration = endTimeData.Duration,
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
HitWindows = obj.HitWindows
};
}
else
@@ -184,6 +188,7 @@ protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, I
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
HitWindows = obj.HitWindows
};
}
else
@@ -193,6 +198,7 @@ protected override IEnumerable<TaikoHitObject> ConvertHitObject(HitObject obj, I
StartTime = obj.StartTime,
Samples = obj.Samples,
IsStrong = strong,
HitWindows = obj.HitWindows
};
}
}
@@ -51,16 +51,10 @@ public List<SampleInfo> Samples

private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;

private HitWindows hitWindows;

/// <summary>
/// The hit windows for this <see cref="HitObject"/>.
/// </summary>
public HitWindows HitWindows
{
get => hitWindows ?? (hitWindows = new HitWindows(overallDifficulty));
protected set => hitWindows = value;
}
public HitWindows HitWindows { get; set; }

private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));

@@ -78,7 +72,11 @@ public void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty d

nestedHitObjects.Clear();
CreateNestedHitObjects();
nestedHitObjects.ForEach(h => h.ApplyDefaults(controlPointInfo, difficulty));
nestedHitObjects.ForEach(h =>
{
h.HitWindows = HitWindows;
h.ApplyDefaults(controlPointInfo, difficulty);
});
}

protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
@@ -89,14 +87,21 @@ protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, Be
Kiai = effectPoint.KiaiMode;
SampleControlPoint = samplePoint;

overallDifficulty = difficulty.OverallDifficulty;
hitWindows = null;
if (HitWindows == null)
HitWindows = CreateHitWindows();
HitWindows?.SetDifficulty(difficulty.OverallDifficulty);

This comment has been minimized.

Copy link
@peppy

peppy May 11, 2018

Member

should CreateHitWindows actually return null?

This comment has been minimized.

Copy link
@smoogipoo

smoogipoo May 11, 2018

Author Contributor

Good point. HitWindows can/should be nullable though (catch).

}

protected virtual void CreateNestedHitObjects()
{
}

protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);

/// <summary>
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
/// This will only be invoked if <see cref="HitWindows"/> hasn't been set externally (e.g. from a <see cref="BeatmapConverter"/>.
/// </summary>
protected virtual HitWindows CreateHitWindows() => null;
}
}
@@ -63,10 +63,10 @@ public class HitWindows
public bool AllowsOk;

/// <summary>
/// Constructs hit windows by fitting a parameter to a 2-part piecewise linear function for each hit window.
/// Sets hit windows with values that correspond to a difficulty parameter.
/// </summary>
/// <param name="difficulty">The parameter.</param>
public HitWindows(double difficulty)
public virtual void SetDifficulty(double difficulty)
{
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
@@ -13,5 +13,7 @@ internal sealed class ConvertHit : HitObject, IHasXPosition, IHasCombo
public float X { get; set; }

public bool NewCombo { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -0,0 +1,32 @@
// 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.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;

namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
public class ConvertHitWindows : HitWindows
{
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
{
{ HitResult.Perfect, (44.8, 38.8, 27.8) },
{ HitResult.Great, (128, 98, 68 ) },
{ HitResult.Good, (194, 164, 134) },
{ HitResult.Ok, (254, 224, 194) },
{ HitResult.Meh, (302, 272, 242) },
{ HitResult.Miss, (376, 346, 316) },
};

public override void SetDifficulty(double difficulty)
{
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
Ok = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Ok]);
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
}
}
}
@@ -12,5 +12,7 @@ internal sealed class ConvertHold : HitObject, IHasXPosition, IHasEndTime
public double EndTime { get; set; }

public double Duration => EndTime - StartTime;

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -13,5 +13,7 @@ internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition, IHasC
public float X { get; set; }

public bool NewCombo { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -15,5 +15,7 @@ internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition
public double Duration => EndTime - StartTime;

public float X { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -18,5 +18,7 @@ internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo
public float Y => Position.Y;

public bool NewCombo { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -0,0 +1,28 @@
// 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.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;

namespace osu.Game.Rulesets.Objects.Legacy.Osu
{
public class ConvertHitWindows : HitWindows
{
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
{
{ HitResult.Great, (160, 100, 40) },
{ HitResult.Good, (280, 200, 120) },
{ HitResult.Meh, (400, 300, 200) },
{ HitResult.Miss, (400, 400, 400) },
};

public override void SetDifficulty(double difficulty)
{
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
}
}
}
@@ -18,5 +18,7 @@ internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasPosition, IHasCo
public float Y => Position.Y;

public bool NewCombo { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -20,5 +20,7 @@ internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition
public float X => Position.X;

public float Y => Position.Y;

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -11,5 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
internal sealed class ConvertHit : HitObject, IHasCombo
{
public bool NewCombo { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -0,0 +1,28 @@
// 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.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;

namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
public class ConvertHitWindows : HitWindows
{
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
{
{ HitResult.Great, (100, 70, 40) },
{ HitResult.Good, (240, 160, 100) },
{ HitResult.Meh, (270, 190, 140) },
{ HitResult.Miss, (400, 400, 400) },
};

public override void SetDifficulty(double difficulty)
{
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
Meh = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Meh]);
Miss = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Miss]);
}
}
}
@@ -11,5 +11,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasCombo
{
public bool NewCombo { get; set; }

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
@@ -13,5 +13,7 @@ internal sealed class ConvertSpinner : HitObject, IHasEndTime
public double EndTime { get; set; }

public double Duration => EndTime - StartTime;

protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.