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
@@ -47,6 +47,8 @@ protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, B

Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
}

protected override HitWindows CreateHitWindows() => null;
}

public enum FruitVisualRepresentation
@@ -4,6 +4,8 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Tests.Visual;
@@ -17,6 +19,14 @@ public class TestCaseManiaHitObjects : OsuTestCase
{
public TestCaseManiaHitObjects()
{
Note note1 = new Note();
Note note2 = new Note();
HoldNote holdNote = new HoldNote { StartTime = 1000 };

note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
holdNote.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

Add(new FillFlowContainer
{
Anchor = Anchor.Centre,
@@ -43,14 +53,14 @@ public TestCaseManiaHitObjects()
RelativeChildSize = new Vector2(1, 10000),
Children = new[]
{
new DrawableNote(new Note(), ManiaAction.Key1)
new DrawableNote(note1, ManiaAction.Key1)
{
Y = 5000,
LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
},
new DrawableNote(new Note(), ManiaAction.Key1)
new DrawableNote(note2, ManiaAction.Key1)
{
Y = 6000,
LifetimeStart = double.MinValue,
@@ -77,13 +87,13 @@ public TestCaseManiaHitObjects()
RelativeChildSize = new Vector2(1, 10000),
Children = new[]
{
new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
new DrawableHoldNote(holdNote, ManiaAction.Key1)
{
Y = 5000,
Height = 1000,
LifetimeStart = double.MinValue,
LifetimeEnd = double.MaxValue,
AccentColour = Color4.Red
AccentColour = Color4.Red,
}
}
}
@@ -8,6 +8,8 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Configuration;
@@ -83,13 +85,16 @@ public TestCaseManiaPlayfield()

int col = rng.Next(0, 4);

var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
var note = new Note { Column = col };
note.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

var drawableNote = new DrawableNote(note, ManiaAction.Key1)
{
AccentColour = playfield.Columns.ElementAt(col).AccentColour
};

playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
playfield.OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect });
playfield.Columns[col].OnJudgement(drawableNote, new ManiaJudgement { Result = HitResult.Perfect });
});
}

@@ -162,32 +167,24 @@ private void createPlayfieldWithNotes(bool inverted = false)

for (double t = start_time; t <= start_time + duration; t += 100)
{
playfield.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 0
}, ManiaAction.Key1));
var note1 = new Note { StartTime = t, Column = 0 };
var note2 = new Note { StartTime = t, Column = 3 };

playfield.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 3
}, ManiaAction.Key4));
note1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
note2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

playfield.Add(new DrawableNote(note1, ManiaAction.Key1));
playfield.Add(new DrawableNote(note2, ManiaAction.Key4));
}

playfield.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 1
}, ManiaAction.Key2));
var holdNote1 = new HoldNote { StartTime = start_time, Duration = duration, Column = 1 };
var holdNote2 = new HoldNote { StartTime = start_time, Duration = duration, Column = 2 };

playfield.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 2
}, ManiaAction.Key3));
holdNote1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
holdNote2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());

playfield.Add(new DrawableHoldNote(holdNote1, ManiaAction.Key2));
playfield.Add(new DrawableHoldNote(holdNote2, ManiaAction.Key3));
}
}
}
@@ -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
};
}
}
@@ -9,6 +9,7 @@
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Tests.Resources;
using OpenTK;
@@ -117,7 +118,7 @@ public void TestDecodeHitObjects()
public void TestParity(string beatmap)
{
var legacy = decode(beatmap, out Beatmap json);
json.ShouldDeepEqual(legacy);
json.WithDeepEqual(legacy).IgnoreProperty(r => r.DeclaringType == typeof(HitWindows)).Assert();
}

/// <summary>
@@ -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,24 @@ 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 can be null to indicate that the <see cref="HitObject"/> has no <see cref="HitWindows"/>.
/// <para>
/// This will only be invoked if <see cref="HitWindows"/> hasn't been set externally (e.g. from a <see cref="BeatmapConverter"/>.
/// </para>
/// </summary>
protected virtual HitWindows CreateHitWindows() => new HitWindows();
}
}
@@ -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();
}
}
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.