Merge branch 'master' into hold-note-freeze

This commit is contained in:
Dean Herbert 2020-08-24 21:49:00 +09:00 committed by GitHub
commit fd0205770b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 17 deletions

View File

@ -0,0 +1,84 @@
// 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.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Catch.Tests.Mods
{
public class TestSceneCatchModRelax : ModTestScene
{
protected override Ruleset CreatePlayerRuleset() => new CatchRuleset();
[Test]
public void TestModRelax() => CreateModTest(new ModTestData
{
Mod = new CatchModRelax(),
Autoplay = false,
PassCondition = passCondition,
Beatmap = new Beatmap
{
HitObjects = new List<HitObject>
{
new Fruit
{
X = CatchPlayfield.CENTER_X,
StartTime = 0
},
new Fruit
{
X = 0,
StartTime = 250
},
new Fruit
{
X = CatchPlayfield.WIDTH,
StartTime = 500
},
new JuiceStream
{
X = CatchPlayfield.CENTER_X,
StartTime = 750,
Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, Vector2.UnitY * 200 })
}
}
}
});
private bool passCondition()
{
var playfield = this.ChildrenOfType<CatchPlayfield>().Single();
switch (Player.ScoreProcessor.Combo.Value)
{
case 0:
InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre);
break;
case 1:
InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.BottomLeft);
break;
case 2:
InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.BottomRight);
break;
case 3:
InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre);
break;
}
return Player.ScoreProcessor.Combo.Value >= 6;
}
}
}

View File

@ -19,25 +19,43 @@ namespace osu.Game.Rulesets.Catch.Tests
{
protected override bool Autoplay => true;
private int hyperDashCount;
private bool inHyperDash;
[Test]
public void TestHyperDash()
{
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
AddUntilStep("wait for right movement", () => getCatcher().Scale.X > 0); // don't check hyperdashing as it happens too fast.
AddUntilStep("wait for left movement", () => getCatcher().Scale.X < 0);
for (int i = 0; i < 3; i++)
AddStep("reset count", () =>
{
AddUntilStep("wait for right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing);
AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing);
inHyperDash = false;
hyperDashCount = 0;
// this needs to be done within the frame stable context due to how quickly hyperdash state changes occur.
Player.DrawableRuleset.FrameStableComponents.OnUpdate += d =>
{
var catcher = Player.ChildrenOfType<CatcherArea>().FirstOrDefault()?.MovableCatcher;
if (catcher == null)
return;
if (catcher.HyperDashing != inHyperDash)
{
inHyperDash = catcher.HyperDashing;
if (catcher.HyperDashing)
hyperDashCount++;
}
};
});
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
for (int i = 0; i < 9; i++)
{
int count = i + 1;
AddUntilStep($"wait for hyperdash #{count}", () => hyperDashCount >= count);
}
AddUntilStep("wait for right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing);
}
private Catcher getCatcher() => Player.ChildrenOfType<CatcherArea>().First().MovableCatcher;
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap

View File

@ -212,6 +212,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
double halfCatcherWidth = Catcher.CalculateCatchWidth(beatmap.BeatmapInfo.BaseDifficulty) / 2;
// Todo: This is wrong. osu!stable calculated hyperdashes using the full catcher size, excluding the margins.
// This should theoretically cause impossible scenarios, but practically, likely due to the size of the playfield, it doesn't seem possible.
// For now, to bring gameplay (and diffcalc!) completely in-line with stable, this code also uses the full catcher size.
halfCatcherWidth /= Catcher.ALLOWED_CATCH_RANGE;
int lastDirection = 0;
double lastExcess = halfCatcherWidth;

View File

@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.Mods
protected override bool OnMouseMove(MouseMoveEvent e)
{
catcher.UpdatePosition(e.MousePosition.X / DrawSize.X);
catcher.UpdatePosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH);
return base.OnMouseMove(e);
}
}

View File

@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Catch.UI
/// <summary>
/// The width of the catcher which can receive fruit. Equivalent to "catchMargin" in osu-stable.
/// </summary>
private const float allowed_catch_range = 0.8f;
public const float ALLOWED_CATCH_RANGE = 0.8f;
/// <summary>
/// The drawable catcher for <see cref="CurrentState"/>.
@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Catch.UI
/// </summary>
/// <param name="scale">The scale of the catcher.</param>
internal static float CalculateCatchWidth(Vector2 scale)
=> CatcherArea.CATCHER_SIZE * Math.Abs(scale.X) * allowed_catch_range;
=> CatcherArea.CATCHER_SIZE * Math.Abs(scale.X) * ALLOWED_CATCH_RANGE;
/// <summary>
/// Calculates the width of the area used for attempting catches in gameplay.

View File

@ -60,7 +60,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
}
[Test]
public void TestApplyDrainRateQueries()
public void TestApplyDrainRateQueriesByDrKeyword()
{
const string query = "dr>2 quite specific dr<:6";
var filterCriteria = new FilterCriteria();
@ -73,6 +73,20 @@ namespace osu.Game.Tests.NonVisual.Filtering
Assert.Less(filterCriteria.DrainRate.Min, 6.1f);
}
[Test]
public void TestApplyDrainRateQueriesByHpKeyword()
{
const string query = "hp>2 quite specific hp<=6";
var filterCriteria = new FilterCriteria();
FilterQueryParser.ApplyQueries(filterCriteria, query);
Assert.AreEqual("quite specific", filterCriteria.SearchText.Trim());
Assert.AreEqual(2, filterCriteria.SearchTerms.Length);
Assert.Greater(filterCriteria.DrainRate.Min, 2.0f);
Assert.Less(filterCriteria.DrainRate.Min, 2.1f);
Assert.Greater(filterCriteria.DrainRate.Max, 6.0f);
Assert.Less(filterCriteria.DrainRate.Min, 6.1f);
}
[Test]
public void TestApplyBPMQueries()
{

View File

@ -11,7 +11,7 @@ namespace osu.Game.Screens.Select
internal static class FilterQueryParser
{
private static readonly Regex query_syntax_regex = new Regex(
@"\b(?<key>stars|ar|dr|cs|divisor|length|objects|bpm|status|creator|artist)(?<op>[=:><]+)(?<value>("".*"")|(\S*))",
@"\b(?<key>stars|ar|dr|hp|cs|divisor|length|objects|bpm|status|creator|artist)(?<op>[=:><]+)(?<value>("".*"")|(\S*))",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
internal static void ApplyQueries(FilterCriteria criteria, string query)
@ -43,6 +43,7 @@ namespace osu.Game.Screens.Select
break;
case "dr" when parseFloatWithPoint(value, out var dr):
case "hp" when parseFloatWithPoint(value, out dr):
updateCriteriaRange(ref criteria.DrainRate, op, dr, 0.1f / 2);
break;