mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 04:59:52 +08:00
Compare commits
240 Commits
@@ -114,7 +114,7 @@ jobs:
|
||||
dotnet-version: "8.0.x"
|
||||
|
||||
- name: Install .NET workloads
|
||||
run: dotnet workload install maui-android
|
||||
run: dotnet workload install android
|
||||
|
||||
- name: Compile
|
||||
run: dotnet build -c Debug osu.Android.slnf
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2024.1025.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2024.1118.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="System.IO.Packaging" Version="8.0.1" />
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageReference Include="Velopack" Version="0.0.869" />
|
||||
<PackageReference Include="Velopack" Version="0.0.915" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 2,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = () => true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = () => true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
||||
Mod = new CatchModRelax(),
|
||||
Autoplay = false,
|
||||
PassCondition = passCondition,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
@@ -106,7 +107,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
AddStep("select everything", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||
AddStep("start drag", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<Column>().First());
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<NoteSelectionBlueprint>().Single(blueprint => blueprint.IsSelected && blueprint.HitObject.StartTime == 0));
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
});
|
||||
AddStep("end drag", () =>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ManiaScoreProcessorTest
|
||||
{
|
||||
[TestCase(ScoreRank.X, 1, HitResult.Perfect)]
|
||||
[TestCase(ScoreRank.X, 0.99, HitResult.Great)]
|
||||
[TestCase(ScoreRank.D, 0.1, HitResult.Great)]
|
||||
[TestCase(ScoreRank.X, 0.99, HitResult.Perfect, HitResult.Great)]
|
||||
[TestCase(ScoreRank.X, 0.99, HitResult.Great, HitResult.Great)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Perfect, HitResult.Good)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Perfect, HitResult.Ok)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Perfect, HitResult.Meh)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Perfect, HitResult.Miss)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Great, HitResult.Good)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Great, HitResult.Ok)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Great, HitResult.Meh)]
|
||||
[TestCase(ScoreRank.S, 0.99, HitResult.Great, HitResult.Miss)]
|
||||
public void TestRanks(ScoreRank expected, double accuracy, params HitResult[] results)
|
||||
{
|
||||
var scoreProcessor = new ManiaScoreProcessor();
|
||||
|
||||
Dictionary<HitResult, int> resultsDict = new Dictionary<HitResult, int>();
|
||||
foreach (var result in results)
|
||||
resultsDict[result] = resultsDict.GetValueOrDefault(result) + 1;
|
||||
|
||||
Assert.That(scoreProcessor.RankFromScore(accuracy, resultsDict), Is.EqualTo(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = true,
|
||||
Beatmap = new ManiaBeatmap(new StageDefinition(1))
|
||||
CreateBeatmap = () => new ManiaBeatmap(new StageDefinition(1))
|
||||
{
|
||||
HitObjects = new List<ManiaHitObject>
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
&& Precision.AlmostEquals(Player.ScoreProcessor.Accuracy.Value, 0.9836, 0.01)
|
||||
&& Player.ScoreProcessor.TotalScore.Value == 946_049,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
|
||||
Difficulty = { OverallDifficulty = 10 },
|
||||
@@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
&& Player.ScoreProcessor.Accuracy.Value == 1
|
||||
&& Player.ScoreProcessor.TotalScore.Value == (long)(1_000_000 * doubleTime.ScoreMultiplier),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
|
||||
Difficulty = { OverallDifficulty = 10 },
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new ManiaModHidden(),
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = Enumerable.Range(1, 100).Select(i => (HitObject)new Note { StartTime = 1000 + 200 * i }).ToList(),
|
||||
Breaks = { new BreakPeriod(2000, 28000) }
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new ManiaModHidden(),
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = Enumerable.Range(1, 100).Select(i => (HitObject)new Note { StartTime = 1000 + 200 * i }).ToList(),
|
||||
Breaks = { new BreakPeriod(2000, 28000) }
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
Mod = new ManiaModPerfect(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(false),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
Mod = new ManiaModPerfect(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(true) && Player.Results.Count == 2,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
Mod = new ManiaModSuddenDeath(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(false),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
|
||||
Mod = new ManiaModSuddenDeath(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(true) && Player.Results.Count == 2,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Skills;
|
||||
using osu.Game.Rulesets.Difficulty.Utils;
|
||||
using osu.Game.Rulesets.Mania.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
@@ -73,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
||||
// 0.0 +--------+-+---------------> Release Difference / ms
|
||||
// release_threshold
|
||||
if (isOverlapping)
|
||||
holdAddition = 1 / (1 + Math.Exp(0.27 * (release_threshold - closestEndTime)));
|
||||
holdAddition = DifficultyCalculationUtils.Logistic(x: closestEndTime, multiplier: 0.27, midpointOffset: release_threshold);
|
||||
|
||||
// Decay and increase individualStrains in own column
|
||||
individualStrains[column] = applyDecay(individualStrains[column], startTime - startTimes[column], individual_decay_base);
|
||||
|
||||
@@ -3,21 +3,39 @@
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||
{
|
||||
public partial class EditBodyPiece : DefaultBodyPiece
|
||||
public partial class EditBodyPiece : CompositeDrawable
|
||||
{
|
||||
private readonly Container border;
|
||||
|
||||
public EditBodyPiece()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
border = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = 3,
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
AccentColour.Value = colours.Yellow;
|
||||
|
||||
Background.Alpha = 0.5f;
|
||||
border.BorderColour = colours.YellowDarker;
|
||||
}
|
||||
|
||||
protected override Drawable CreateForeground() => base.CreateForeground().With(d => d.Alpha = 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
@@ -26,10 +27,11 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||
{
|
||||
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
InternalChild = new DefaultNotePiece();
|
||||
InternalChild = new EditNotePiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 1,
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@@ -60,19 +62,23 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||
{
|
||||
base.OnDrag(e);
|
||||
Dragging?.Invoke(e.ScreenSpaceMousePosition);
|
||||
updateState();
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
base.OnDragEnd(e);
|
||||
DragEnded?.Invoke();
|
||||
updateState();
|
||||
}
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
InternalChild.Colour = Colour4.White;
|
||||
|
||||
var colour = colours.Yellow;
|
||||
|
||||
if (IsHovered)
|
||||
if (IsHovered || IsDragged)
|
||||
colour = colour.Lighten(1);
|
||||
|
||||
Colour = colour;
|
||||
|
||||
@@ -2,28 +2,63 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components
|
||||
{
|
||||
public partial class EditNotePiece : CompositeDrawable
|
||||
{
|
||||
private readonly Container border;
|
||||
private readonly Box box;
|
||||
|
||||
[Resolved]
|
||||
private Column? column { get; set; }
|
||||
|
||||
public EditNotePiece()
|
||||
{
|
||||
Height = DefaultNotePiece.NOTE_HEIGHT;
|
||||
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
|
||||
InternalChild = new DefaultNotePiece();
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
border = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = 3,
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
},
|
||||
box = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 3,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Colour = colours.Yellow;
|
||||
border.BorderColour = colours.YellowDark;
|
||||
box.Colour = colours.YellowLight;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (column != null)
|
||||
Scale = new Vector2(1, column.ScrollingInfo.Direction.Value == ScrollingDirection.Down ? 1 : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
@@ -17,9 +19,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
public partial class HoldNotePlacementBlueprint : ManiaPlacementBlueprint<HoldNote>
|
||||
{
|
||||
private readonly EditBodyPiece bodyPiece;
|
||||
private readonly EditNotePiece headPiece;
|
||||
private readonly EditNotePiece tailPiece;
|
||||
private EditBodyPiece bodyPiece = null!;
|
||||
private Circle headPiece = null!;
|
||||
private Circle tailPiece = null!;
|
||||
|
||||
[Resolved]
|
||||
private IScrollingInfo scrollingInfo { get; set; } = null!;
|
||||
@@ -28,14 +30,29 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
|
||||
public HoldNotePlacementBlueprint()
|
||||
: base(new HoldNote())
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
bodyPiece = new EditBodyPiece { Origin = Anchor.TopCentre },
|
||||
headPiece = new EditNotePiece { Origin = Anchor.Centre },
|
||||
tailPiece = new EditNotePiece { Origin = Anchor.Centre }
|
||||
headPiece = new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colours.Yellow,
|
||||
Height = 10
|
||||
},
|
||||
tailPiece = new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colours.Yellow,
|
||||
Height = 10
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osuTK;
|
||||
|
||||
@@ -17,9 +17,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
public partial class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint<HoldNote>
|
||||
{
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private IEditorChangeHandler? changeHandler { get; set; }
|
||||
|
||||
@@ -29,9 +26,12 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
[Resolved]
|
||||
private IPositionSnapProvider? positionSnapProvider { get; set; }
|
||||
|
||||
private EditBodyPiece body = null!;
|
||||
private EditHoldNoteEndPiece head = null!;
|
||||
private EditHoldNoteEndPiece tail = null!;
|
||||
|
||||
protected new DrawableHoldNote DrawableObject => (DrawableHoldNote)base.DrawableObject;
|
||||
|
||||
public HoldNoteSelectionBlueprint(HoldNote hold)
|
||||
: base(hold)
|
||||
{
|
||||
@@ -42,9 +42,17 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
body = new EditBodyPiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
},
|
||||
head = new EditHoldNoteEndPiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
DragStarted = () => changeHandler?.BeginChange(),
|
||||
Dragging = pos =>
|
||||
{
|
||||
@@ -64,6 +72,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
tail = new EditHoldNoteEndPiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
DragStarted = () => changeHandler?.BeginChange(),
|
||||
Dragging = pos =>
|
||||
{
|
||||
@@ -79,19 +89,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
},
|
||||
DragEnded = () => changeHandler?.EndChange(),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = 1,
|
||||
BorderColour = colours.Yellow,
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -99,11 +96,23 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
base.Update();
|
||||
|
||||
head.Height = DrawableObject.Head.DrawHeight;
|
||||
head.Y = HitObjectContainer.PositionAtTime(HitObject.Head.StartTime, HitObject.StartTime);
|
||||
tail.Height = DrawableObject.Tail.DrawHeight;
|
||||
tail.Y = HitObjectContainer.PositionAtTime(HitObject.Tail.StartTime, HitObject.StartTime);
|
||||
Height = HitObjectContainer.LengthAtTime(HitObject.StartTime, HitObject.EndTime) + tail.DrawHeight;
|
||||
}
|
||||
|
||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
Origin = direction.NewValue == ScrollingDirection.Down ? Anchor.BottomCentre : Anchor.TopCentre;
|
||||
|
||||
foreach (var child in InternalChildren)
|
||||
child.Anchor = Origin;
|
||||
|
||||
head.Scale = tail.Scale = body.Scale = new Vector2(1, direction.NewValue == ScrollingDirection.Down ? 1 : -1);
|
||||
}
|
||||
|
||||
public override Quad SelectionQuad => ScreenSpaceDrawQuad;
|
||||
|
||||
public override Vector2 ScreenSpaceSelectionPoint => head.ScreenSpaceDrawQuad.Centre;
|
||||
|
||||
@@ -37,16 +37,10 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
directionBindable.BindValueChanged(onDirectionChanged, true);
|
||||
directionBindable.BindValueChanged(OnDirectionChanged, true);
|
||||
}
|
||||
|
||||
private void onDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
var anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||
Anchor = Origin = anchor;
|
||||
foreach (var child in InternalChildren)
|
||||
child.Anchor = child.Origin = anchor;
|
||||
}
|
||||
protected abstract void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osuTK.Input;
|
||||
|
||||
@@ -12,14 +14,25 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
public partial class NotePlacementBlueprint : ManiaPlacementBlueprint<Note>
|
||||
{
|
||||
private readonly EditNotePiece piece;
|
||||
private Circle piece = null!;
|
||||
|
||||
public NotePlacementBlueprint()
|
||||
: base(new Note())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
InternalChild = piece = new EditNotePiece { Origin = Anchor.Centre };
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Masking = true;
|
||||
|
||||
InternalChild = piece = new Circle
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colours.Yellow,
|
||||
Height = 10
|
||||
};
|
||||
}
|
||||
|
||||
public override void UpdateTimeAndPosition(SnapResult result)
|
||||
|
||||
@@ -1,18 +1,42 @@
|
||||
// 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 osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
public partial class NoteSelectionBlueprint : ManiaSelectionBlueprint<Note>
|
||||
{
|
||||
private readonly EditNotePiece notePiece;
|
||||
|
||||
public NoteSelectionBlueprint(Note note)
|
||||
: base(note)
|
||||
{
|
||||
AddInternal(new EditNotePiece { RelativeSizeAxes = Axes.X });
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Origin = Anchor.BottomCentre;
|
||||
AddInternal(notePiece = new EditNotePiece
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
notePiece.Height = DrawableObject.DrawHeight;
|
||||
}
|
||||
|
||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> direction)
|
||||
{
|
||||
notePiece.Scale = new Vector2(1, direction.NewValue == ScrollingDirection.Down ? 1 : -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
public partial class EditorColumn : Column
|
||||
{
|
||||
public EditorColumn(int index, bool isSpecial)
|
||||
: base(index, isSpecial)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnNewDrawableHitObject(DrawableHitObject drawableHitObject)
|
||||
{
|
||||
base.OnNewDrawableHitObject(drawableHitObject);
|
||||
drawableHitObject.ApplyCustomUpdateState += (dho, state) =>
|
||||
{
|
||||
switch (dho)
|
||||
{
|
||||
// hold note heads are exempt from what follows due to the "freezing" mechanic
|
||||
// which already ensures they'll never fade away on their own.
|
||||
case DrawableHoldNoteHead:
|
||||
break;
|
||||
|
||||
// mania features instantaneous hitobject fade-outs.
|
||||
// this means that without manual intervention stopping the clock at the precise time of hitting the object
|
||||
// means the object will fade out.
|
||||
// this is anti-user in editor contexts, as the user is expecting to continue the see the note on the receptor line.
|
||||
// therefore, apply a crude workaround to prevent it from going away.
|
||||
default:
|
||||
{
|
||||
if (state == ArmedState.Hit)
|
||||
dho.FadeTo(1).Delay(1).FadeOut().Expire();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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 osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
public partial class EditorStage : Stage
|
||||
{
|
||||
public EditorStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction columnStartAction)
|
||||
: base(firstColumnIndex, definition, ref columnStartAction)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Column CreateColumn(int index, bool isSpecial) => new EditorColumn(index, isSpecial);
|
||||
}
|
||||
}
|
||||
@@ -13,5 +13,8 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
: base(stages)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Stage CreateStage(int firstColumnIndex, StageDefinition stageDefinition, ref ManiaAction columnAction)
|
||||
=> new EditorStage(firstColumnIndex, stageDefinition, ref columnAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
base.Update();
|
||||
|
||||
if (screenWithTimeline?.TimelineArea.Timeline != null)
|
||||
drawableRuleset.TimelineTimeRange = EditorClock.TrackLength / screenWithTimeline.TimelineArea.Timeline.CurrentZoom / 2;
|
||||
drawableRuleset.TimelineTimeRange = EditorClock.TrackLength / screenWithTimeline.TimelineArea.Timeline.CurrentZoom.Value / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Scoring
|
||||
{
|
||||
@@ -58,6 +59,24 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
||||
return GetBaseScoreForResult(result);
|
||||
}
|
||||
|
||||
public override ScoreRank RankFromScore(double accuracy, IReadOnlyDictionary<HitResult, int> results)
|
||||
{
|
||||
ScoreRank rank = base.RankFromScore(accuracy, results);
|
||||
|
||||
if (rank != ScoreRank.S)
|
||||
return rank;
|
||||
|
||||
// SS is expected as long as all hitobjects have been hit with either a GREAT or PERFECT result.
|
||||
|
||||
bool anyImperfect =
|
||||
results.GetValueOrDefault(HitResult.Good) > 0
|
||||
|| results.GetValueOrDefault(HitResult.Ok) > 0
|
||||
|| results.GetValueOrDefault(HitResult.Meh) > 0
|
||||
|| results.GetValueOrDefault(HitResult.Miss) > 0;
|
||||
|
||||
return anyImperfect ? rank : ScoreRank.X;
|
||||
}
|
||||
|
||||
private class JudgementOrderComparer : IComparer<HitObject>
|
||||
{
|
||||
public static readonly JudgementOrderComparer DEFAULT = new JudgementOrderComparer();
|
||||
|
||||
@@ -54,7 +54,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
},
|
||||
columnBackgrounds = new ColumnFlow<Drawable>(stageDefinition)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Masking = false,
|
||||
},
|
||||
new HitTargetInsetContainer
|
||||
{
|
||||
@@ -126,8 +127,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
},
|
||||
new Container
|
||||
{
|
||||
X = isLastColumn ? -0.16f : 0,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = rightLineWidth,
|
||||
Scale = new Vector2(0.740f, 1),
|
||||
|
||||
@@ -28,6 +28,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
private readonly FillFlowContainer<Container<TContent>> columns;
|
||||
private readonly StageDefinition stageDefinition;
|
||||
|
||||
public new bool Masking
|
||||
{
|
||||
get => base.Masking;
|
||||
set => base.Masking = value;
|
||||
}
|
||||
|
||||
public ColumnFlow(StageDefinition stageDefinition)
|
||||
{
|
||||
this.stageDefinition = stageDefinition;
|
||||
|
||||
@@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
@@ -71,7 +72,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
|
||||
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||
{
|
||||
var newStage = new Stage(firstColumnIndex, stageDefinitions[i], ref columnAction);
|
||||
var newStage = CreateStage(firstColumnIndex, stageDefinitions[i], ref columnAction);
|
||||
|
||||
playfieldGrid.Content[0][i] = newStage;
|
||||
|
||||
@@ -82,6 +83,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
}
|
||||
}
|
||||
|
||||
[Pure]
|
||||
protected virtual Stage CreateStage(int firstColumnIndex, StageDefinition stageDefinition, ref ManiaAction columnAction) => new Stage(firstColumnIndex, stageDefinition, ref columnAction);
|
||||
|
||||
public override void Add(HitObject hitObject) => getStageByColumn(((ManiaHitObject)hitObject).Column).Add(hitObject);
|
||||
|
||||
public override bool Remove(HitObject hitObject) => getStageByColumn(((ManiaHitObject)hitObject).Column).Remove(hitObject);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
@@ -134,12 +135,14 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
bool isSpecial = definition.IsSpecialColumn(i);
|
||||
|
||||
var column = new Column(firstColumnIndex + i, isSpecial)
|
||||
var action = columnStartAction;
|
||||
columnStartAction++;
|
||||
var column = CreateColumn(firstColumnIndex + i, isSpecial).With(c =>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 1,
|
||||
Action = { Value = columnStartAction++ }
|
||||
};
|
||||
c.RelativeSizeAxes = Axes.Both;
|
||||
c.Width = 1;
|
||||
c.Action.Value = action;
|
||||
});
|
||||
|
||||
topLevelContainer.Add(column.TopLevelContainer.CreateProxy());
|
||||
columnBackgrounds.Add(column.BackgroundContainer.CreateProxy());
|
||||
@@ -154,6 +157,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
RegisterPool<BarLine, DrawableBarLine>(50, 200);
|
||||
}
|
||||
|
||||
[Pure]
|
||||
protected virtual Column CreateColumn(int index, bool isSpecial) => new Column(index, isSpecial);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISkinSource skin)
|
||||
{
|
||||
|
||||
@@ -17,4 +17,8 @@
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.17.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||
@@ -24,38 +25,57 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
||||
|
||||
[Test]
|
||||
public void TestTouchInputAfterTouchingComposeArea()
|
||||
public void TestTouchInputPlaceHitCircleDirectly()
|
||||
{
|
||||
AddStep("tap circle", () => tap(this.ChildrenOfType<EditorRadioButton>().Single(b => b.Button.Label == "HitCircle")));
|
||||
|
||||
// this input is just for interacting with compose area
|
||||
AddStep("tap playfield", () => tap(this.ChildrenOfType<Playfield>().Single()));
|
||||
|
||||
AddStep("move current time", () => InputManager.Key(Key.Right));
|
||||
|
||||
AddStep("tap to place circle", () => tap(this.ChildrenOfType<Playfield>().Single().ToScreenSpace(new Vector2(10, 10))));
|
||||
AddStep("tap to place circle", () => tap(this.ChildrenOfType<Playfield>().Single()));
|
||||
AddAssert("circle placed correctly", () =>
|
||||
{
|
||||
var circle = (HitCircle)EditorBeatmap.HitObjects.Single(h => h.StartTime == EditorClock.CurrentTimeAccurate);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(circle.Position.X, Is.EqualTo(10f).Within(0.01f));
|
||||
Assert.That(circle.Position.Y, Is.EqualTo(10f).Within(0.01f));
|
||||
Assert.That(circle.Position.X, Is.EqualTo(256f).Within(0.01f));
|
||||
Assert.That(circle.Position.Y, Is.EqualTo(192f).Within(0.01f));
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
AddStep("tap slider", () => tap(this.ChildrenOfType<EditorRadioButton>().Single(b => b.Button.Label == "Slider")));
|
||||
[Test]
|
||||
public void TestTouchInputPlaceCircleAfterTouchingComposeArea()
|
||||
{
|
||||
AddStep("tap circle", () => tap(this.ChildrenOfType<EditorRadioButton>().Single(b => b.Button.Label == "HitCircle")));
|
||||
|
||||
// this input is just for interacting with compose area
|
||||
AddStep("tap playfield", () => tap(this.ChildrenOfType<Playfield>().Single()));
|
||||
AddAssert("circle placed", () => EditorBeatmap.HitObjects.Single(h => h.StartTime == EditorClock.CurrentTimeAccurate) is HitCircle);
|
||||
|
||||
AddStep("move current time", () => InputManager.Key(Key.Right));
|
||||
AddStep("move forward", () => InputManager.Key(Key.Right));
|
||||
|
||||
AddStep("tap to place circle", () => tap(this.ChildrenOfType<Playfield>().Single()));
|
||||
AddAssert("circle placed correctly", () =>
|
||||
{
|
||||
var circle = (HitCircle)EditorBeatmap.HitObjects.Single(h => h.StartTime == EditorClock.CurrentTimeAccurate);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(circle.Position.X, Is.EqualTo(256f).Within(0.01f));
|
||||
Assert.That(circle.Position.Y, Is.EqualTo(192f).Within(0.01f));
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTouchInputPlaceSliderDirectly()
|
||||
{
|
||||
AddStep("tap slider", () => tap(this.ChildrenOfType<EditorRadioButton>().Single(b => b.Button.Label == "Slider")));
|
||||
|
||||
AddStep("hold to draw slider", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, this.ChildrenOfType<Playfield>().Single().ToScreenSpace(new Vector2(50, 20)))));
|
||||
AddStep("drag to draw", () => InputManager.MoveTouchTo(new Touch(TouchSource.Touch1, this.ChildrenOfType<Playfield>().Single().ToScreenSpace(new Vector2(200, 50)))));
|
||||
AddAssert("selection not initiated", () => this.ChildrenOfType<DragBox>().All(d => d.State == Visibility.Hidden));
|
||||
AddAssert("blueprint visible", () => this.ChildrenOfType<SliderPlacementBlueprint>().Single().Alpha > 0);
|
||||
AddStep("end", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, InputManager.CurrentState.Touch.GetTouchPosition(TouchSource.Touch1)!.Value)));
|
||||
AddAssert("slider placed correctly", () =>
|
||||
{
|
||||
@@ -76,12 +96,55 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
});
|
||||
}
|
||||
|
||||
private void tap(Drawable drawable) => tap(drawable.ScreenSpaceDrawQuad.Centre);
|
||||
[Test]
|
||||
public void TestTouchInputPlaceSliderAfterTouchingComposeArea()
|
||||
{
|
||||
AddStep("tap slider", () => tap(this.ChildrenOfType<EditorRadioButton>().Single(b => b.Button.Label == "Slider")));
|
||||
|
||||
AddStep("tap playfield", () => tap(this.ChildrenOfType<Playfield>().Single()));
|
||||
AddStep("tap and hold another spot", () => hold(this.ChildrenOfType<Playfield>().Single(), new Vector2(50, 0)));
|
||||
AddUntilStep("wait for slider placement", () => EditorBeatmap.HitObjects.SingleOrDefault(h => h.StartTime == EditorClock.CurrentTimeAccurate) is Slider);
|
||||
AddStep("end", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, InputManager.CurrentState.Touch.GetTouchPosition(TouchSource.Touch1)!.Value)));
|
||||
|
||||
AddStep("move forward", () => InputManager.Key(Key.Right));
|
||||
|
||||
AddStep("hold to draw slider", () => InputManager.BeginTouch(new Touch(TouchSource.Touch1, this.ChildrenOfType<Playfield>().Single().ToScreenSpace(new Vector2(50, 20)))));
|
||||
AddStep("drag to draw", () => InputManager.MoveTouchTo(new Touch(TouchSource.Touch1, this.ChildrenOfType<Playfield>().Single().ToScreenSpace(new Vector2(200, 50)))));
|
||||
AddAssert("selection not initiated", () => this.ChildrenOfType<DragBox>().All(d => d.State == Visibility.Hidden));
|
||||
AddAssert("blueprint visible", () => this.ChildrenOfType<SliderPlacementBlueprint>().Single().IsPresent);
|
||||
AddStep("end", () => InputManager.EndTouch(new Touch(TouchSource.Touch1, InputManager.CurrentState.Touch.GetTouchPosition(TouchSource.Touch1)!.Value)));
|
||||
AddAssert("slider placed correctly", () =>
|
||||
{
|
||||
var slider = (Slider)EditorBeatmap.HitObjects.Single(h => h.StartTime == EditorClock.CurrentTimeAccurate);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(slider.Position.X, Is.EqualTo(50f).Within(0.01f));
|
||||
Assert.That(slider.Position.Y, Is.EqualTo(20f).Within(0.01f));
|
||||
Assert.That(slider.Path.ControlPoints.Count, Is.EqualTo(2));
|
||||
Assert.That(slider.Path.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
|
||||
// the final position may be slightly off from the mouse position when drawing, account for that.
|
||||
Assert.That(slider.Path.ControlPoints[1].Position.X, Is.EqualTo(150).Within(5));
|
||||
Assert.That(slider.Path.ControlPoints[1].Position.Y, Is.EqualTo(30).Within(5));
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void tap(Drawable drawable, Vector2 offset = default) => tap(drawable.ToScreenSpace(drawable.LayoutRectangle.Centre + offset));
|
||||
|
||||
private void tap(Vector2 position)
|
||||
{
|
||||
InputManager.BeginTouch(new Touch(TouchSource.Touch1, position));
|
||||
hold(position);
|
||||
InputManager.EndTouch(new Touch(TouchSource.Touch1, position));
|
||||
}
|
||||
|
||||
private void hold(Drawable drawable, Vector2 offset = default) => hold(drawable.ToScreenSpace(drawable.LayoutRectangle.Centre + offset));
|
||||
|
||||
private void hold(Vector2 position)
|
||||
{
|
||||
InputManager.BeginTouch(new Touch(TouchSource.Touch1, position));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModAlternate(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 4,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModAlternate(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 1,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModAlternate(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 1,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModAlternate(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 2,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
Breaks =
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Autoplay = true,
|
||||
Mod = mod,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects =
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
public void TestNoAdjustment() => CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new OsuModDifficultyAdjust(),
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Player.GameplayClockContainer.CurrentTime < 1000 && Player.ChildrenOfType<ModFlashlight<OsuHitObject>.Flashlight>().Single().FlashlightDim > 0;
|
||||
return Player.GameplayState.HasPassed && !sliderDimmedBeforeStartTime;
|
||||
},
|
||||
Beatmap = new OsuBeatmap
|
||||
CreateBeatmap = () => new OsuBeatmap
|
||||
{
|
||||
HitObjects = new List<OsuHitObject>
|
||||
{
|
||||
@@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Player.GameplayClockContainer.CurrentTime >= 1000 && Player.ChildrenOfType<ModFlashlight<OsuHitObject>.Flashlight>().Single().FlashlightDim > 0;
|
||||
return Player.GameplayState.HasPassed && sliderDimmed;
|
||||
},
|
||||
Beatmap = new OsuBeatmap
|
||||
CreateBeatmap = () => new OsuBeatmap
|
||||
{
|
||||
HitObjects = new List<OsuHitObject>
|
||||
{
|
||||
@@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Player.GameplayClockContainer.CurrentTime >= 1000 && Player.ChildrenOfType<ModFlashlight<OsuHitObject>.Flashlight>().Single().FlashlightDim > 0;
|
||||
return Player.GameplayState.HasPassed && sliderDimmed;
|
||||
},
|
||||
Beatmap = new OsuBeatmap
|
||||
CreateBeatmap = () => new OsuBeatmap
|
||||
{
|
||||
HitObjects = new List<OsuHitObject>
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new TestOsuModHidden(),
|
||||
Autoplay = true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new TestOsuModHidden(),
|
||||
Autoplay = true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new TestOsuModHidden(),
|
||||
Autoplay = true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new OsuModHidden { OnlyFadeApproachCircles = { Value = true } },
|
||||
Autoplay = true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
public void TestCorrectReflections([Values] OsuModMirror.MirrorType type, [Values] bool withStrictTracking) => CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = true,
|
||||
Beatmap = new OsuBeatmap
|
||||
CreateBeatmap = () => new OsuBeatmap
|
||||
{
|
||||
HitObjects =
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = () => true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = () => true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
},
|
||||
Autoplay = true,
|
||||
PassCondition = () => true,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModPerfect(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(true),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
AngleSharpness = { Value = angleSharpness }
|
||||
},
|
||||
Beatmap = jumpBeatmap,
|
||||
CreateBeatmap = jumpBeatmap,
|
||||
Autoplay = true,
|
||||
PassCondition = () => true
|
||||
});
|
||||
@@ -50,15 +50,15 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
AngleSharpness = { Value = angleSharpness }
|
||||
},
|
||||
Beatmap = streamBeatmap,
|
||||
CreateBeatmap = streamBeatmap,
|
||||
Autoplay = true,
|
||||
PassCondition = () => true
|
||||
});
|
||||
|
||||
private OsuBeatmap jumpBeatmap =>
|
||||
private OsuBeatmap jumpBeatmap() =>
|
||||
createHitCircleBeatmap(new[] { 100, 200, 300, 400 }, 8, 300, 2 * 300);
|
||||
|
||||
private OsuBeatmap streamBeatmap =>
|
||||
private OsuBeatmap streamBeatmap() =>
|
||||
createHitCircleBeatmap(new[] { 10, 20, 30, 40, 50, 60, 70, 80 }, 16, 150, 4 * 150);
|
||||
|
||||
private OsuBeatmap createHitCircleBeatmap(IEnumerable<int> spacings, int objectsPerSpacing, int interval, int beatLength)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModSingleTap(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 2,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModSingleTap(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 1,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModSingleTap(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 1,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModSingleTap(),
|
||||
PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 2,
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
Breaks =
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new OsuModSpunOut(),
|
||||
Autoplay = false,
|
||||
Beatmap = singleSpinnerBeatmap,
|
||||
CreateBeatmap = singleSpinnerBeatmap,
|
||||
PassCondition = () =>
|
||||
{
|
||||
// Bind to the first spinner's results for further tracking.
|
||||
@@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mods = mods,
|
||||
Autoplay = false,
|
||||
Beatmap = singleSpinnerBeatmap,
|
||||
CreateBeatmap = singleSpinnerBeatmap,
|
||||
PassCondition = () =>
|
||||
{
|
||||
var counter = Player.ChildrenOfType<SpinnerSpmCalculator>().SingleOrDefault();
|
||||
@@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new OsuModSpunOut(),
|
||||
Autoplay = false,
|
||||
Beatmap = singleSpinnerBeatmap,
|
||||
CreateBeatmap = singleSpinnerBeatmap,
|
||||
PassCondition = () =>
|
||||
{
|
||||
// Bind to the first spinner's results for further tracking.
|
||||
@@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
});
|
||||
}
|
||||
|
||||
private Beatmap singleSpinnerBeatmap => new Beatmap
|
||||
private Beatmap singleSpinnerBeatmap() => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
{
|
||||
Mod = new OsuModStrictTracking(),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModSuddenDeath(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(false),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||
Mod = new OsuModSuddenDeath(),
|
||||
PassCondition = () => ((ModFailConditionTestPlayer)Player).CheckFailed(true),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
Autoplay = false,
|
||||
Mod = new TestAutoMod(),
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
},
|
||||
@@ -47,18 +47,16 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[Test]
|
||||
public void TestMissViaNotHitting()
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
};
|
||||
|
||||
var hitWindows = new OsuHitWindows();
|
||||
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
|
||||
hitWindows.SetDifficulty(IBeatmapDifficultyInfo.DEFAULT_DIFFICULTY);
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Beatmap = beatmap,
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
|
||||
},
|
||||
PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset >= hitWindows.WindowFor(HitResult.Meh) && !Player.Results[0].IsHit
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Utils;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
@@ -33,6 +34,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
var osuLastObj = (OsuDifficultyHitObject)current.Previous(0);
|
||||
var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1);
|
||||
|
||||
const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS;
|
||||
const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER;
|
||||
|
||||
// Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle.
|
||||
double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime;
|
||||
|
||||
@@ -77,14 +81,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
wideAngleBonus = calcWideAngleBonus(currAngle);
|
||||
acuteAngleBonus = calcAcuteAngleBonus(currAngle);
|
||||
|
||||
if (osuCurrObj.StrainTime > 100) // Only buff deltaTime exceeding 300 bpm 1/2.
|
||||
if (DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2) < 300) // Only buff deltaTime exceeding 300 bpm 1/2.
|
||||
acuteAngleBonus = 0;
|
||||
else
|
||||
{
|
||||
acuteAngleBonus *= calcAcuteAngleBonus(lastAngle) // Multiply by previous angle, we don't want to buff unless this is a wiggle type pattern.
|
||||
* Math.Min(angleBonus, 125 / osuCurrObj.StrainTime) // The maximum velocity we buff is equal to 125 / strainTime
|
||||
* Math.Min(angleBonus, diameter * 1.25 / osuCurrObj.StrainTime) // The maximum velocity we buff is equal to 125 / strainTime
|
||||
* Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, (100 - osuCurrObj.StrainTime) / 25)), 2) // scale buff from 150 bpm 1/4 to 200 bpm 1/4
|
||||
* Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.LazyJumpDistance, 50, 100) - 50) / 50), 2); // Buff distance exceeding 50 (radius) up to 100 (diameter).
|
||||
* Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.LazyJumpDistance, radius, diameter) - radius) / radius), 2); // Buff distance exceeding radius up to diameter.
|
||||
}
|
||||
|
||||
// Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute.
|
||||
@@ -104,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
double distRatio = Math.Pow(Math.Sin(Math.PI / 2 * Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity)), 2);
|
||||
|
||||
// Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing.
|
||||
double overlapVelocityBuff = Math.Min(125 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity));
|
||||
double overlapVelocityBuff = Math.Min(diameter * 1.25 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity));
|
||||
|
||||
velocityChangeBonus = overlapVelocityBuff * distRatio;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Utils;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
@@ -120,7 +121,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
islandCount.Count++;
|
||||
|
||||
// repeated island (ex: triplet -> triplet)
|
||||
double power = logistic(island.Delta, 2.75, 0.24, 14);
|
||||
double power = DifficultyCalculationUtils.Logistic(island.Delta, maxValue: 2.75, multiplier: 0.24, midpointOffset: 58.33);
|
||||
effectiveRatio *= Math.Min(3.0 / islandCount.Count, Math.Pow(1.0 / islandCount.Count, power));
|
||||
|
||||
islandCounts[countIndex] = (islandCount.Island, islandCount.Count);
|
||||
@@ -172,8 +173,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
return Math.Sqrt(4 + rhythmComplexitySum * rhythm_overall_multiplier) / 2.0; // produces multiplier that can be applied to strain. range [1, infinity) (not really though)
|
||||
}
|
||||
|
||||
private static double logistic(double x, double maxValue, double multiplier, double offset) => (maxValue / (1 + Math.Pow(Math.E, offset - (multiplier * x))));
|
||||
|
||||
private class Island : IEquatable<Island>
|
||||
{
|
||||
private readonly double deltaDifferenceEpsilon;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Utils;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
@@ -10,8 +11,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
{
|
||||
public static class SpeedEvaluator
|
||||
{
|
||||
private const double single_spacing_threshold = 125; // 1.25 circles distance between centers
|
||||
private const double min_speed_bonus = 75; // ~200BPM
|
||||
private const double single_spacing_threshold = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers
|
||||
private const double min_speed_bonus = 200; // 200 BPM 1/4th
|
||||
private const double speed_balancing_factor = 40;
|
||||
private const double distance_multiplier = 0.94;
|
||||
|
||||
@@ -43,8 +44,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
||||
double speedBonus = 0.0;
|
||||
|
||||
// Add additional scaling bonus for streams/bursts higher than 200bpm
|
||||
if (strainTime < min_speed_bonus)
|
||||
speedBonus = 0.75 * Math.Pow((min_speed_bonus - strainTime) / speed_balancing_factor, 2);
|
||||
if (DifficultyCalculationUtils.MillisecondsToBPM(strainTime) > min_speed_bonus)
|
||||
speedBonus = 0.75 * Math.Pow((DifficultyCalculationUtils.BPMToMilliseconds(min_speed_bonus) - strainTime) / speed_balancing_factor, 2);
|
||||
|
||||
double travelDistance = osuPrevObj?.TravelDistance ?? 0;
|
||||
double distance = travelDistance + osuCurrObj.MinimumJumpDistance;
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
||||
/// </summary>
|
||||
public const int NORMALISED_RADIUS = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||
|
||||
public const int NORMALISED_DIAMETER = NORMALISED_RADIUS * 2;
|
||||
|
||||
public const int MIN_DELTA_TIME = 25;
|
||||
|
||||
private const float maximum_slider_radius = NORMALISED_RADIUS * 2.4f;
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
/// </summary>
|
||||
protected virtual double ReducedStrainBaseline => 0.75;
|
||||
|
||||
protected double Difficulty;
|
||||
|
||||
protected OsuStrainSkill(Mod[] mods)
|
||||
: base(mods)
|
||||
{
|
||||
@@ -32,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
|
||||
public override double DifficultyValue()
|
||||
{
|
||||
Difficulty = 0;
|
||||
double difficulty = 0;
|
||||
double weight = 1;
|
||||
|
||||
// Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871).
|
||||
@@ -52,11 +50,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
// We're sorting from highest to lowest strain.
|
||||
foreach (double strain in strains.OrderDescending())
|
||||
{
|
||||
Difficulty += strain * weight;
|
||||
difficulty += strain * weight;
|
||||
weight *= DecayWeight;
|
||||
}
|
||||
|
||||
return Difficulty;
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
public static double DifficultyToPerformance(double difficulty) => Math.Pow(5.0 * Math.Max(1.0, difficulty / 0.0675) - 4.0, 3.0) / 100000.0;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osuTK;
|
||||
@@ -31,12 +32,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
||||
public override void EndPlacement(bool commit)
|
||||
{
|
||||
if (!commit && PlacementActive != PlacementState.Finished)
|
||||
{
|
||||
gridToolboxGroup.StartPosition.Value = originalOrigin;
|
||||
gridToolboxGroup.Spacing.Value = originalSpacing;
|
||||
if (!gridToolboxGroup.GridLinesRotation.Disabled)
|
||||
gridToolboxGroup.GridLinesRotation.Value = originalRotation;
|
||||
}
|
||||
resetGridState();
|
||||
|
||||
base.EndPlacement(commit);
|
||||
|
||||
@@ -103,6 +99,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
||||
|
||||
public override void UpdateTimeAndPosition(SnapResult result)
|
||||
{
|
||||
if (State.Value == Visibility.Hidden)
|
||||
return;
|
||||
|
||||
var pos = ToLocalSpace(result.ScreenSpacePosition);
|
||||
|
||||
if (PlacementActive != PlacementState.Active)
|
||||
@@ -122,5 +121,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
resetGridState();
|
||||
}
|
||||
|
||||
private void resetGridState()
|
||||
{
|
||||
gridToolboxGroup.StartPosition.Value = originalOrigin;
|
||||
gridToolboxGroup.Spacing.Value = originalSpacing;
|
||||
if (!gridToolboxGroup.GridLinesRotation.Disabled)
|
||||
gridToolboxGroup.GridLinesRotation.Value = originalRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
return true;
|
||||
}
|
||||
|
||||
// this allows sliders to be drawn outside compose area (after starting from a point within the compose area).
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || PlacementActive == PlacementState.Active;
|
||||
|
||||
// ReceivePositionalInputAtSubTree generally always returns true when masking is disabled, but we don't want that,
|
||||
// otherwise a slider path tooltip will be displayed anywhere in the editor (outside compose area).
|
||||
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
private void beginNewSegment(PathControlPoint lastPoint)
|
||||
{
|
||||
segmentStart = lastPoint;
|
||||
|
||||
@@ -50,9 +50,14 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
[Resolved]
|
||||
private HitObjectComposer composer { get; set; } = null!;
|
||||
|
||||
private Bindable<TernaryState> newComboState = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var selectionHandler = (EditorSelectionHandler)composer.BlueprintContainer.SelectionHandler;
|
||||
newComboState = selectionHandler.SelectionNewComboState.GetBoundCopy();
|
||||
|
||||
AllowableAnchors = new[] { Anchor.CentreLeft, Anchor.CentreRight };
|
||||
|
||||
Child = new FillFlowContainer
|
||||
@@ -120,10 +125,11 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
changeHandler?.BeginChange();
|
||||
began = true;
|
||||
|
||||
distanceSnapInput.Current.BindValueChanged(_ => tryCreatePolygon());
|
||||
offsetAngleInput.Current.BindValueChanged(_ => tryCreatePolygon());
|
||||
repeatCountInput.Current.BindValueChanged(_ => tryCreatePolygon());
|
||||
pointInput.Current.BindValueChanged(_ => tryCreatePolygon());
|
||||
distanceSnapInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon));
|
||||
offsetAngleInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon));
|
||||
repeatCountInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon));
|
||||
pointInput.Current.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon));
|
||||
newComboState.BindValueChanged(_ => Scheduler.AddOnce(tryCreatePolygon));
|
||||
tryCreatePolygon();
|
||||
}
|
||||
|
||||
@@ -138,39 +144,69 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
double length = distanceSnapInput.Current.Value * velocity * timeSpacing;
|
||||
float polygonRadius = (float)(length / (2 * Math.Sin(double.Pi / pointInput.Current.Value)));
|
||||
|
||||
editorBeatmap.RemoveRange(insertedCircles);
|
||||
insertedCircles.Clear();
|
||||
int totalPoints = pointInput.Current.Value * repeatCountInput.Current.Value;
|
||||
|
||||
var selectionHandler = (EditorSelectionHandler)composer.BlueprintContainer.SelectionHandler;
|
||||
bool first = true;
|
||||
|
||||
for (int i = 1; i <= pointInput.Current.Value * repeatCountInput.Current.Value; ++i)
|
||||
if (insertedCircles.Count > totalPoints)
|
||||
{
|
||||
float angle = float.DegreesToRadians(offsetAngleInput.Current.Value) + i * (2 * float.Pi / pointInput.Current.Value);
|
||||
var position = OsuPlayfield.BASE_SIZE / 2 + new Vector2(polygonRadius * float.Cos(angle), polygonRadius * float.Sin(angle));
|
||||
editorBeatmap.RemoveRange(insertedCircles.GetRange(totalPoints, insertedCircles.Count - totalPoints));
|
||||
insertedCircles.RemoveRange(totalPoints, insertedCircles.Count - totalPoints);
|
||||
}
|
||||
|
||||
var circle = new HitCircle
|
||||
var newlyAdded = new List<HitCircle>();
|
||||
|
||||
for (int i = 0; i < totalPoints; ++i)
|
||||
{
|
||||
float angle = float.DegreesToRadians(offsetAngleInput.Current.Value) + (i + 1) * (2 * float.Pi / pointInput.Current.Value);
|
||||
var position = OsuPlayfield.BASE_SIZE / 2 + new Vector2(polygonRadius * float.Cos(angle), polygonRadius * float.Sin(angle));
|
||||
bool newCombo = i == 0 && newComboState.Value == TernaryState.True;
|
||||
|
||||
HitCircle circle;
|
||||
|
||||
if (i < insertedCircles.Count)
|
||||
{
|
||||
Position = position,
|
||||
StartTime = startTime,
|
||||
NewCombo = first && selectionHandler.SelectionNewComboState.Value == TernaryState.True,
|
||||
};
|
||||
// TODO: probably ensure samples also follow current ternary status (not trivial)
|
||||
circle.Samples.Add(circle.CreateHitSampleInfo());
|
||||
circle = insertedCircles[i];
|
||||
|
||||
circle.Position = position;
|
||||
circle.StartTime = startTime;
|
||||
circle.NewCombo = newCombo;
|
||||
|
||||
editorBeatmap.Update(circle);
|
||||
}
|
||||
else
|
||||
{
|
||||
circle = new HitCircle
|
||||
{
|
||||
Position = position,
|
||||
StartTime = startTime,
|
||||
NewCombo = newCombo,
|
||||
};
|
||||
|
||||
newlyAdded.Add(circle);
|
||||
|
||||
// TODO: probably ensure samples also follow current ternary status (not trivial)
|
||||
circle.Samples.Add(circle.CreateHitSampleInfo());
|
||||
}
|
||||
|
||||
if (position.X < 0 || position.Y < 0 || position.X > OsuPlayfield.BASE_SIZE.X || position.Y > OsuPlayfield.BASE_SIZE.Y)
|
||||
{
|
||||
commitButton.Enabled.Value = false;
|
||||
editorBeatmap.RemoveRange(insertedCircles);
|
||||
insertedCircles.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
insertedCircles.Add(circle);
|
||||
startTime = beatSnapProvider.SnapTime(startTime + timeSpacing);
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
editorBeatmap.AddRange(insertedCircles);
|
||||
var previousNewComboState = newComboState.Value;
|
||||
|
||||
insertedCircles.AddRange(newlyAdded);
|
||||
editorBeatmap.AddRange(newlyAdded);
|
||||
|
||||
// When adding new hitObjects, newCombo state will get reset to false when no objects are selected.
|
||||
// Since this is the case when this popover is showing, we need to restore the previous newCombo state
|
||||
newComboState.Value = previousNewComboState;
|
||||
|
||||
commitButton.Enabled.Value = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// 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;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModBloom : Mod, IApplicableToScoreProcessor, IUpdatableByPlayfield, IApplicableToPlayer
|
||||
{
|
||||
public override string Name => "Bloom";
|
||||
public override string Acronym => "BM";
|
||||
public override ModType Type => ModType.Fun;
|
||||
public override LocalisableString Description => "The cursor blooms into.. a larger cursor!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
protected const float MIN_SIZE = 1;
|
||||
protected const float TRANSITION_DURATION = 100;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight), typeof(OsuModNoScope), typeof(ModTouchDevice) };
|
||||
|
||||
protected readonly BindableNumber<int> CurrentCombo = new BindableInt();
|
||||
protected readonly IBindable<bool> IsBreakTime = new Bindable<bool>();
|
||||
|
||||
private float currentSize;
|
||||
|
||||
[SettingSource(
|
||||
"Max size at combo",
|
||||
"The combo count at which the cursor reaches its maximum size",
|
||||
SettingControlType = typeof(SettingsSlider<int, RoundedSliderBar<int>>)
|
||||
)]
|
||||
public BindableInt MaxSizeComboCount { get; } = new BindableInt(50)
|
||||
{
|
||||
MinValue = 5,
|
||||
MaxValue = 100,
|
||||
};
|
||||
|
||||
[SettingSource(
|
||||
"Final size multiplier",
|
||||
"The multiplier applied to cursor size when combo reaches maximum",
|
||||
SettingControlType = typeof(SettingsSlider<float, RoundedSliderBar<float>>)
|
||||
)]
|
||||
public BindableFloat MaxCursorSize { get; } = new BindableFloat(10f)
|
||||
{
|
||||
MinValue = 5f,
|
||||
MaxValue = 15f,
|
||||
Precision = 0.5f,
|
||||
};
|
||||
|
||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
||||
|
||||
public void ApplyToPlayer(Player player)
|
||||
{
|
||||
IsBreakTime.BindTo(player.IsBreakTime);
|
||||
}
|
||||
|
||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
||||
{
|
||||
CurrentCombo.BindTo(scoreProcessor.Combo);
|
||||
CurrentCombo.BindValueChanged(combo =>
|
||||
{
|
||||
currentSize = Math.Clamp(MaxCursorSize.Value * ((float)combo.NewValue / MaxSizeComboCount.Value), MIN_SIZE, MaxCursorSize.Value);
|
||||
}, true);
|
||||
}
|
||||
|
||||
public void Update(Playfield playfield)
|
||||
{
|
||||
OsuCursor cursor = (OsuCursor)(playfield.Cursor!.ActiveCursor);
|
||||
|
||||
if (IsBreakTime.Value)
|
||||
cursor.ModScaleAdjust.Value = 1;
|
||||
else
|
||||
cursor.ModScaleAdjust.Value = (float)Interpolation.Lerp(cursor.ModScaleAdjust.Value, currentSize, Math.Clamp(cursor.Time.Elapsed / TRANSITION_DURATION, 0, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public partial class OsuModFlashlight : ModFlashlight<OsuHitObject>, IApplicableToDrawableHitObject
|
||||
{
|
||||
public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1;
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModBlinds)).ToArray();
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModBloom), typeof(OsuModBlinds) }).ToArray();
|
||||
|
||||
private const double default_follow_delay = 120;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public override LocalisableString Description => "Where's the cursor?";
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModBloom) };
|
||||
|
||||
private PeriodTracker spinnerPeriods = null!;
|
||||
|
||||
public override BindableInt HiddenComboCount { get; } = new BindableInt(10)
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModTouchDevice : ModTouchDevice
|
||||
{
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot) }).ToArray();
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModBloom) }).ToArray();
|
||||
public override bool Ranked => UsesDefaultConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,8 @@ namespace osu.Game.Rulesets.Osu
|
||||
new OsuModFreezeFrame(),
|
||||
new OsuModBubbles(),
|
||||
new OsuModSynesthesia(),
|
||||
new OsuModDepth()
|
||||
new OsuModDepth(),
|
||||
new OsuModBloom()
|
||||
};
|
||||
|
||||
case ModType.System:
|
||||
|
||||
@@ -14,6 +14,7 @@ using osu.Framework.Graphics.Rendering.Vertices;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Shaders.Types;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Graphics.Visualisation;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Timing;
|
||||
@@ -23,6 +24,7 @@ using osuTK.Graphics.ES30;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
{
|
||||
[DrawVisualiserHidden]
|
||||
public partial class CursorTrail : Drawable, IRequireHighFrequencyMousePosition
|
||||
{
|
||||
private const int max_sprites = 2048;
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
public IBindable<float> CursorScale => cursorScale;
|
||||
|
||||
/// <summary>
|
||||
/// Mods which want to adjust cursor size should do so via this bindable.
|
||||
/// </summary>
|
||||
public readonly Bindable<float> ModScaleAdjust = new Bindable<float>(1);
|
||||
|
||||
private readonly Bindable<float> cursorScale = new BindableFloat(1);
|
||||
|
||||
private Bindable<float> userCursorScale = null!;
|
||||
@@ -67,6 +72,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
autoCursorScale = config.GetBindable<bool>(OsuSetting.AutoCursorSize);
|
||||
autoCursorScale.ValueChanged += _ => cursorScale.Value = CalculateCursorScale();
|
||||
|
||||
ModScaleAdjust.ValueChanged += _ => cursorScale.Value = CalculateCursorScale();
|
||||
|
||||
cursorScale.BindValueChanged(e => cursorScaleContainer.Scale = new Vector2(e.NewValue), true);
|
||||
}
|
||||
|
||||
@@ -90,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
protected virtual float CalculateCursorScale()
|
||||
{
|
||||
float scale = userCursorScale.Value;
|
||||
float scale = userCursorScale.Value * ModScaleAdjust.Value;
|
||||
|
||||
if (autoCursorScale.Value && state != null)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Project References">
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
|
||||
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -31,40 +31,42 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
const double hit_time = 1;
|
||||
|
||||
var beatmap = new Beatmap<TaikoHitObject>
|
||||
{
|
||||
HitObjects = new List<TaikoHitObject>
|
||||
{
|
||||
new Hit
|
||||
{
|
||||
Type = HitType.Rim,
|
||||
StartTime = hit_time,
|
||||
},
|
||||
new Hit
|
||||
{
|
||||
Type = HitType.Centre,
|
||||
StartTime = hit_time * 2,
|
||||
},
|
||||
},
|
||||
BeatmapInfo =
|
||||
{
|
||||
Difficulty = new BeatmapDifficulty
|
||||
{
|
||||
SliderTickRate = 4,
|
||||
OverallDifficulty = 0,
|
||||
},
|
||||
Ruleset = new TaikoRuleset().RulesetInfo
|
||||
},
|
||||
};
|
||||
|
||||
beatmap.ControlPointInfo.Add(0, new EffectControlPoint { ScrollSpeed = 0.1f });
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new TaikoModHidden(),
|
||||
Autoplay = true,
|
||||
PassCondition = checkAllMaxResultJudgements(2),
|
||||
Beatmap = beatmap,
|
||||
CreateBeatmap = () =>
|
||||
{
|
||||
var beatmap = new Beatmap<TaikoHitObject>
|
||||
{
|
||||
HitObjects = new List<TaikoHitObject>
|
||||
{
|
||||
new Hit
|
||||
{
|
||||
Type = HitType.Rim,
|
||||
StartTime = hit_time,
|
||||
},
|
||||
new Hit
|
||||
{
|
||||
Type = HitType.Centre,
|
||||
StartTime = hit_time * 2,
|
||||
},
|
||||
},
|
||||
BeatmapInfo =
|
||||
{
|
||||
Difficulty = new BeatmapDifficulty
|
||||
{
|
||||
SliderTickRate = 4,
|
||||
OverallDifficulty = 0,
|
||||
},
|
||||
Ruleset = new TaikoRuleset().RulesetInfo
|
||||
},
|
||||
};
|
||||
|
||||
beatmap.ControlPointInfo.Add(0, new EffectControlPoint { ScrollSpeed = 0.1f });
|
||||
return beatmap;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,26 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
[Test]
|
||||
public void TestRelax()
|
||||
{
|
||||
var beatmap = new TaikoBeatmap
|
||||
var beatmapForReplay = createBeatmap();
|
||||
|
||||
foreach (var ho in beatmapForReplay.HitObjects)
|
||||
ho.ApplyDefaults(beatmapForReplay.ControlPointInfo, beatmapForReplay.Difficulty);
|
||||
|
||||
var replay = new TaikoAutoGenerator(beatmapForReplay).Generate();
|
||||
|
||||
foreach (var frame in replay.Frames.OfType<TaikoReplayFrame>().Where(r => r.Actions.Any()))
|
||||
frame.Actions = [TaikoAction.LeftCentre];
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new TaikoModRelax(),
|
||||
CreateBeatmap = createBeatmap,
|
||||
ReplayFrames = replay.Frames,
|
||||
Autoplay = false,
|
||||
PassCondition = () => Player.ScoreProcessor.HasCompleted.Value && Player.ScoreProcessor.Accuracy.Value == 1,
|
||||
});
|
||||
|
||||
TaikoBeatmap createBeatmap() => new TaikoBeatmap
|
||||
{
|
||||
HitObjects =
|
||||
{
|
||||
@@ -25,22 +44,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
new Swell { StartTime = 1250, Duration = 500 },
|
||||
}
|
||||
};
|
||||
foreach (var ho in beatmap.HitObjects)
|
||||
ho.ApplyDefaults(beatmap.ControlPointInfo, beatmap.Difficulty);
|
||||
|
||||
var replay = new TaikoAutoGenerator(beatmap).Generate();
|
||||
|
||||
foreach (var frame in replay.Frames.OfType<TaikoReplayFrame>().Where(r => r.Actions.Any()))
|
||||
frame.Actions = [TaikoAction.LeftCentre];
|
||||
|
||||
CreateModTest(new ModTestData
|
||||
{
|
||||
Mod = new TaikoModRelax(),
|
||||
Beatmap = beatmap,
|
||||
ReplayFrames = replay.Frames,
|
||||
Autoplay = false,
|
||||
PassCondition = () => Player.ScoreProcessor.HasCompleted.Value && Player.ScoreProcessor.Accuracy.Value == 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
Mod = new TaikoModSingleTap(),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
Mod = new TaikoModSingleTap(),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
Mod = new TaikoModSingleTap(),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
Mod = new TaikoModSingleTap(),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>
|
||||
{
|
||||
@@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
|
||||
{
|
||||
Mod = new TaikoModSingleTap(),
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
Breaks =
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Utils;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data;
|
||||
@@ -11,26 +12,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
{
|
||||
public class ColourEvaluator
|
||||
{
|
||||
/// <summary>
|
||||
/// A sigmoid function. It gives a value between (middle - height/2) and (middle + height/2).
|
||||
/// </summary>
|
||||
/// <param name="val">The input value.</param>
|
||||
/// <param name="center">The center of the sigmoid, where the largest gradient occurs and value is equal to middle.</param>
|
||||
/// <param name="width">The radius of the sigmoid, outside of which values are near the minimum/maximum.</param>
|
||||
/// <param name="middle">The middle of the sigmoid output.</param>
|
||||
/// <param name="height">The height of the sigmoid output. This will be equal to max value - min value.</param>
|
||||
private static double sigmoid(double val, double center, double width, double middle, double height)
|
||||
{
|
||||
double sigmoid = Math.Tanh(Math.E * -(val - center) / width);
|
||||
return sigmoid * (height / 2) + middle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate the difficulty of the first note of a <see cref="MonoStreak"/>.
|
||||
/// </summary>
|
||||
public static double EvaluateDifficultyOf(MonoStreak monoStreak)
|
||||
{
|
||||
return sigmoid(monoStreak.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(monoStreak.Parent) * 0.5;
|
||||
return DifficultyCalculationUtils.Logistic(exponent: Math.E * monoStreak.Index - 2 * Math.E) * EvaluateDifficultyOf(monoStreak.Parent) * 0.5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
/// </summary>
|
||||
public static double EvaluateDifficultyOf(AlternatingMonoPattern alternatingMonoPattern)
|
||||
{
|
||||
return sigmoid(alternatingMonoPattern.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(alternatingMonoPattern.Parent);
|
||||
return DifficultyCalculationUtils.Logistic(exponent: Math.E * alternatingMonoPattern.Index - 2 * Math.E) * EvaluateDifficultyOf(alternatingMonoPattern.Parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -46,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators
|
||||
/// </summary>
|
||||
public static double EvaluateDifficultyOf(RepeatingHitPatterns repeatingHitPattern)
|
||||
{
|
||||
return 2 * (1 - sigmoid(repeatingHitPattern.RepetitionInterval, 2, 2, 0.5, 1));
|
||||
return 2 * (1 - DifficultyCalculationUtils.Logistic(exponent: Math.E * repeatingHitPattern.RepetitionInterval - 2 * Math.E));
|
||||
}
|
||||
|
||||
public static double EvaluateDifficultyOf(DifficultyHitObject hitObject)
|
||||
|
||||
@@ -84,8 +84,11 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
|
||||
protected virtual double ComputeTimeRange()
|
||||
{
|
||||
// Adjust when we're using constant algorithm to not be sluggish.
|
||||
double multiplier = VisualisationMethod == ScrollVisualisationMethod.Constant ? 4 * Beatmap.Difficulty.SliderMultiplier : 1;
|
||||
// Using the constant algorithm results in a sluggish scroll speed that's equal to 60 BPM.
|
||||
// We need to adjust it to the expected default scroll speed (BPM * base SV multiplier).
|
||||
double multiplier = VisualisationMethod == ScrollVisualisationMethod.Constant
|
||||
? (Beatmap.BeatmapInfo.BPM * Beatmap.Difficulty.SliderMultiplier) / 60
|
||||
: 1;
|
||||
return PlayfieldAdjustmentContainer.ComputeTimeRange() / multiplier;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
// 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.IO;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual;
|
||||
using MemoryStream = System.IO.MemoryStream;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
[HeadlessTest]
|
||||
public partial class LegacyBeatmapExporterTest : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; } = null!;
|
||||
|
||||
[Test]
|
||||
public void TestObjectsSnappedAfterTruncatingExport()
|
||||
{
|
||||
IWorkingBeatmap beatmap = null!;
|
||||
MemoryStream outStream = null!;
|
||||
|
||||
// Ensure importer encoding is correct
|
||||
AddStep("import beatmap", () => beatmap = importBeatmapFromArchives(@"decimal-timing-beatmap.olz"));
|
||||
AddAssert("timing point has decimal offset", () => beatmap.Beatmap.ControlPointInfo.TimingPoints[0].Time, () => Is.EqualTo(284.725).Within(0.001));
|
||||
AddAssert("kiai has decimal offset", () => beatmap.Beatmap.ControlPointInfo.EffectPoints[0].Time, () => Is.EqualTo(28520.019).Within(0.001));
|
||||
AddAssert("hit object has decimal offset", () => beatmap.Beatmap.HitObjects[0].StartTime, () => Is.EqualTo(28520.019).Within(0.001));
|
||||
|
||||
// Ensure exporter legacy conversion is correct
|
||||
AddStep("export", () =>
|
||||
{
|
||||
outStream = new MemoryStream();
|
||||
|
||||
new LegacyBeatmapExporter(LocalStorage)
|
||||
.ExportToStream((BeatmapSetInfo)beatmap.BeatmapInfo.BeatmapSet!, outStream, null);
|
||||
});
|
||||
|
||||
AddStep("import beatmap again", () => beatmap = importBeatmapFromStream(outStream));
|
||||
AddAssert("timing point has truncated offset", () => beatmap.Beatmap.ControlPointInfo.TimingPoints[0].Time, () => Is.EqualTo(284).Within(0.001));
|
||||
AddAssert("kiai is snapped", () => beatmap.Beatmap.ControlPointInfo.EffectPoints[0].Time, () => Is.EqualTo(28519).Within(0.001));
|
||||
AddAssert("hit object is snapped", () => beatmap.Beatmap.HitObjects[0].StartTime, () => Is.EqualTo(28519).Within(0.001));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExportStability()
|
||||
{
|
||||
IWorkingBeatmap beatmap = null!;
|
||||
MemoryStream firstExport = null!;
|
||||
MemoryStream secondExport = null!;
|
||||
|
||||
// Ensure importer encoding is correct
|
||||
AddStep("import beatmap", () => beatmap = importBeatmapFromArchives(@"legacy-export-stability-test.olz"));
|
||||
AddStep("export once", () =>
|
||||
{
|
||||
firstExport = new MemoryStream();
|
||||
|
||||
new LegacyBeatmapExporter(LocalStorage)
|
||||
.ExportToStream((BeatmapSetInfo)beatmap.BeatmapInfo.BeatmapSet!, firstExport, null);
|
||||
});
|
||||
|
||||
AddStep("import beatmap again", () => beatmap = importBeatmapFromStream(firstExport));
|
||||
AddStep("export again", () =>
|
||||
{
|
||||
secondExport = new MemoryStream();
|
||||
|
||||
new LegacyBeatmapExporter(LocalStorage)
|
||||
.ExportToStream((BeatmapSetInfo)beatmap.BeatmapInfo.BeatmapSet!, secondExport, null);
|
||||
});
|
||||
|
||||
const string osu_filename = @"legacy export - stability test (spaceman_atlas) [].osu";
|
||||
|
||||
AddAssert("exports are identical",
|
||||
() => getStringContentsOf(osu_filename, firstExport.GetBuffer()),
|
||||
() => Is.EqualTo(getStringContentsOf(osu_filename, secondExport.GetBuffer())));
|
||||
|
||||
string getStringContentsOf(string filename, byte[] archiveBytes)
|
||||
{
|
||||
using var memoryStream = new MemoryStream(archiveBytes);
|
||||
using var archiveReader = new ZipArchiveReader(memoryStream);
|
||||
byte[] fileContent = archiveReader.GetStream(filename).ReadAllBytesToArray();
|
||||
return Encoding.UTF8.GetString(fileContent);
|
||||
}
|
||||
}
|
||||
|
||||
private IWorkingBeatmap importBeatmapFromStream(Stream stream)
|
||||
{
|
||||
var imported = beatmaps.Import(new ImportTask(stream, "filename.osz")).GetResultSafely();
|
||||
return imported.AsNonNull().PerformRead(s => beatmaps.GetWorkingBeatmap(s.Beatmaps[0]));
|
||||
}
|
||||
|
||||
private IWorkingBeatmap importBeatmapFromArchives(string filename)
|
||||
{
|
||||
var imported = beatmaps.Import(new ImportTask(TestResources.OpenResource($@"Archives/{filename}"), filename)).GetResultSafely();
|
||||
return imported.AsNonNull().PerformRead(s => beatmaps.GetWorkingBeatmap(s.Beatmaps[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,6 +148,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
[TestCase("tags too", false)]
|
||||
[TestCase("version", false)]
|
||||
[TestCase("an auteur", true)]
|
||||
[TestCase("unit", false)]
|
||||
public void TestCriteriaMatchingTerms(string terms, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
@@ -175,6 +176,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
[TestCase("\"Artist\"!", true)]
|
||||
[TestCase("\"The Artist\"!", false)]
|
||||
[TestCase("\"the artist\"!", false)]
|
||||
[TestCase("\"unit tests\"!", false)]
|
||||
[TestCase("\"\\\"", true)] // nasty case, covers properly escaping user input in underlying regex.
|
||||
public void TestCriteriaMatchingExactTerms(string terms, bool filtered)
|
||||
{
|
||||
|
||||
@@ -501,6 +501,18 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
Assert.That(visibleBeatmaps, Is.EqualTo(expectedBeatmapIndexes));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestApplySourceQueries()
|
||||
{
|
||||
const string query = "find me songs with source=\"unit tests\" please";
|
||||
var filterCriteria = new FilterCriteria();
|
||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||
Assert.AreEqual("find me songs with please", filterCriteria.SearchText.Trim());
|
||||
Assert.AreEqual(5, filterCriteria.SearchTerms.Length);
|
||||
Assert.AreEqual("unit tests", filterCriteria.Source.SearchTerm);
|
||||
Assert.That(filterCriteria.Source.MatchMode, Is.EqualTo(FilterCriteria.MatchMode.IsolatedPhrase));
|
||||
}
|
||||
|
||||
private class CustomFilterCriteria : IRulesetFilterCriteria
|
||||
{
|
||||
public string? CustomValue { get; set; }
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
||||
var newRoom = new Room();
|
||||
newRoom.CopyFrom(SelectedRoom.Value);
|
||||
|
||||
newRoom.RoomID.Value = null;
|
||||
newRoom.RoomID = null;
|
||||
MultiplayerClient.RoomSetupAction = room =>
|
||||
{
|
||||
room.State = MultiplayerRoomState.Playing;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -12,6 +12,7 @@ using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
using osu.Game.Rulesets;
|
||||
@@ -205,7 +206,9 @@ namespace osu.Game.Tests.Visual.Collections
|
||||
|
||||
AddStep("click first delete button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(dialog.ChildrenOfType<DrawableCollectionListItem.DeleteButton>().First(), new Vector2(5, 0));
|
||||
InputManager.MoveMouseTo(dialog
|
||||
.ChildrenOfType<DrawableCollectionListItem>().Single(i => i.Model.Value.Name == "1")
|
||||
.ChildrenOfType<DrawableCollectionListItem.DeleteButton>().Single(), new Vector2(5, 0));
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
@@ -213,9 +216,11 @@ namespace osu.Game.Tests.Visual.Collections
|
||||
assertCollectionCount(1);
|
||||
assertCollectionName(0, "2");
|
||||
|
||||
AddStep("click first delete button", () =>
|
||||
AddStep("click second delete button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(dialog.ChildrenOfType<DrawableCollectionListItem.DeleteButton>().First(), new Vector2(5, 0));
|
||||
InputManager.MoveMouseTo(dialog
|
||||
.ChildrenOfType<DrawableCollectionListItem>().Single(i => i.Model.Value.Name == "2")
|
||||
.ChildrenOfType<DrawableCollectionListItem.DeleteButton>().Single(), new Vector2(5, 0));
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
@@ -310,7 +315,7 @@ namespace osu.Game.Tests.Visual.Collections
|
||||
|
||||
AddStep("focus first collection", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(firstItem = dialog.ChildrenOfType<DrawableCollectionListItem>().First());
|
||||
InputManager.MoveMouseTo(firstItem = dialog.ChildrenOfType<DrawableCollectionListItem>().Single(i => i.Model.Value.Name == "1"));
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
@@ -333,10 +338,44 @@ namespace osu.Game.Tests.Visual.Collections
|
||||
AddUntilStep("collection has new name", () => first.Name == "First");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSearch()
|
||||
{
|
||||
BeatmapCollection first = null!;
|
||||
|
||||
AddStep("add two collections", () =>
|
||||
{
|
||||
Realm.Write(r =>
|
||||
{
|
||||
r.Add(new[]
|
||||
{
|
||||
first = new BeatmapCollection(name: "1"),
|
||||
new BeatmapCollection(name: "2"),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
assertCollectionName(0, "1");
|
||||
assertCollectionName(1, "2");
|
||||
|
||||
AddStep("search for 1", () => dialog.ChildrenOfType<SearchTextBox>().Single().Current.Value = "1");
|
||||
|
||||
assertCollectionCount(1);
|
||||
|
||||
AddStep("change first collection name", () => Realm.Write(_ => first.Name = "First"));
|
||||
|
||||
assertCollectionCount(0);
|
||||
|
||||
AddStep("search for first", () => dialog.ChildrenOfType<SearchTextBox>().Single().Current.Value = "firs");
|
||||
|
||||
assertCollectionCount(1);
|
||||
}
|
||||
|
||||
private void assertCollectionCount(int count)
|
||||
=> AddUntilStep($"{count} collections shown", () => dialog.ChildrenOfType<DrawableCollectionListItem>().Count() == count + 1); // +1 for placeholder
|
||||
=> AddUntilStep($"{count} collections shown", () => dialog.ChildrenOfType<DrawableCollectionListItem>().Count(i => i.IsPresent) == count + 1); // +1 for placeholder
|
||||
|
||||
private void assertCollectionName(int index, string name)
|
||||
=> AddUntilStep($"item {index + 1} has correct name", () => dialog.ChildrenOfType<DrawableCollectionListItem>().ElementAt(index).ChildrenOfType<TextBox>().First().Text == name);
|
||||
=> AddUntilStep($"item {index + 1} has correct name",
|
||||
() => dialog.ChildrenOfType<DrawableCollectionList>().Single().OrderedItems.ElementAt(index).ChildrenOfType<TextBox>().First().Text == name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,18 +39,18 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = { Value = 1234 },
|
||||
Name = { Value = "Daily Challenge: June 4, 2024" },
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
|
||||
{
|
||||
RequiredMods = [new APIMod(new OsuModTraceable())],
|
||||
AllowedMods = [new APIMod(new OsuModDoubleTime())]
|
||||
}
|
||||
},
|
||||
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
|
||||
Category = { Value = RoomCategory.DailyChallenge }
|
||||
],
|
||||
EndDate = DateTimeOffset.Now.AddHours(12),
|
||||
Category = RoomCategory.DailyChallenge
|
||||
};
|
||||
|
||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||
@@ -62,18 +62,18 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = { Value = 1234 },
|
||||
Name = { Value = "Daily Challenge: June 4, 2024" },
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
|
||||
{
|
||||
RequiredMods = [new APIMod(new OsuModTraceable())],
|
||||
AllowedMods = [new APIMod(new OsuModDoubleTime())]
|
||||
}
|
||||
},
|
||||
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
|
||||
Category = { Value = RoomCategory.DailyChallenge }
|
||||
],
|
||||
EndDate = DateTimeOffset.Now.AddHours(12),
|
||||
Category = RoomCategory.DailyChallenge
|
||||
};
|
||||
|
||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||
@@ -91,18 +91,18 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
RoomID = { Value = 1234 },
|
||||
Name = { Value = "Daily Challenge: June 4, 2024" },
|
||||
RoomID = 1234,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
|
||||
{
|
||||
RequiredMods = [new APIMod(new OsuModTraceable())],
|
||||
AllowedMods = [new APIMod(new OsuModDoubleTime())]
|
||||
}
|
||||
},
|
||||
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
|
||||
Category = { Value = RoomCategory.DailyChallenge }
|
||||
],
|
||||
EndDate = DateTimeOffset.Now.AddHours(12),
|
||||
Category = RoomCategory.DailyChallenge
|
||||
};
|
||||
|
||||
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
|
||||
|
||||
@@ -26,11 +26,6 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
|
||||
private readonly Bindable<Room> room = new Bindable<Room>(new Room());
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => new CachedModelDependencyContainer<Room>(base.CreateChildDependencies(parent))
|
||||
{
|
||||
Model = { BindTarget = room }
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestBasicAppearance()
|
||||
{
|
||||
@@ -98,7 +93,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
Origin = Anchor.Centre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DailyChallengeTimeRemainingRing(),
|
||||
new DailyChallengeTimeRemainingRing(room.Value),
|
||||
breakdown = new DailyChallengeScoreBreakdown(),
|
||||
}
|
||||
}
|
||||
@@ -125,8 +120,8 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
AddSliderStep("update time remaining", 0f, 1f, 0f, progress =>
|
||||
{
|
||||
var startedTimeAgo = TimeSpan.FromHours(24) * progress;
|
||||
room.Value.StartDate.Value = DateTimeOffset.Now - startedTimeAgo;
|
||||
room.Value.EndDate.Value = room.Value.StartDate.Value.Value.AddDays(1);
|
||||
room.Value.StartDate = DateTimeOffset.Now - startedTimeAgo;
|
||||
room.Value.EndDate = room.Value.StartDate.Value.AddDays(1);
|
||||
});
|
||||
AddStep("add normal score", () =>
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
Add(metadataClient);
|
||||
|
||||
// add button to observe for daily challenge changes and perform its logic.
|
||||
Add(new DailyChallengeButton(@"button-default-select", new Color4(102, 68, 204, 255), _ => { }, 0, Key.D));
|
||||
Add(new DailyChallengeButton(@"button-default-select", new Color4(102, 68, 204, 255), (_, _) => { }, 0, Key.D));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -68,19 +68,19 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
API.Perform(new CreateRoomRequest(room = new Room
|
||||
{
|
||||
RoomID = { Value = roomId },
|
||||
Name = { Value = "Daily Challenge: June 4, 2024" },
|
||||
RoomID = roomId,
|
||||
Name = "Daily Challenge: June 4, 2024",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(CreateAPIBeatmap(new OsuRuleset().RulesetInfo))
|
||||
{
|
||||
RequiredMods = [new APIMod(new OsuModTraceable())],
|
||||
AllowedMods = [new APIMod(new OsuModDoubleTime())]
|
||||
}
|
||||
},
|
||||
StartDate = { Value = DateTimeOffset.Now },
|
||||
EndDate = { Value = DateTimeOffset.Now.AddHours(24) },
|
||||
Category = { Value = RoomCategory.DailyChallenge }
|
||||
],
|
||||
StartDate = DateTimeOffset.Now,
|
||||
EndDate = DateTimeOffset.Now.AddHours(24),
|
||||
Category = RoomCategory.DailyChallenge
|
||||
}));
|
||||
});
|
||||
AddStep("signal client", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = roomId }));
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
return false;
|
||||
};
|
||||
});
|
||||
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = { Value = 1 } }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
|
||||
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = 1 }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
@@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
return false;
|
||||
};
|
||||
});
|
||||
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = { Value = 1 } }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
|
||||
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = 1 }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
|
||||
@@ -18,11 +18,6 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
{
|
||||
private readonly Bindable<Room> room = new Bindable<Room>(new Room());
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => new CachedModelDependencyContainer<Room>(base.CreateChildDependencies(parent))
|
||||
{
|
||||
Model = { BindTarget = room }
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||
|
||||
@@ -38,7 +33,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4,
|
||||
},
|
||||
ring = new DailyChallengeTimeRemainingRing
|
||||
ring = new DailyChallengeTimeRemainingRing(room.Value)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
@@ -59,29 +54,29 @@ namespace osu.Game.Tests.Visual.DailyChallenge
|
||||
|
||||
AddStep("just started", () =>
|
||||
{
|
||||
room.Value.StartDate.Value = DateTimeOffset.Now.AddMinutes(-1);
|
||||
room.Value.EndDate.Value = room.Value.StartDate.Value.Value.AddDays(1);
|
||||
room.Value.StartDate = DateTimeOffset.Now.AddMinutes(-1);
|
||||
room.Value.EndDate = room.Value.StartDate.Value.AddDays(1);
|
||||
});
|
||||
AddStep("midway through", () =>
|
||||
{
|
||||
room.Value.StartDate.Value = DateTimeOffset.Now.AddHours(-12);
|
||||
room.Value.EndDate.Value = room.Value.StartDate.Value.Value.AddDays(1);
|
||||
room.Value.StartDate = DateTimeOffset.Now.AddHours(-12);
|
||||
room.Value.EndDate = room.Value.StartDate.Value.AddDays(1);
|
||||
});
|
||||
AddStep("nearing end", () =>
|
||||
{
|
||||
room.Value.StartDate.Value = DateTimeOffset.Now.AddDays(-1).AddMinutes(8);
|
||||
room.Value.EndDate.Value = room.Value.StartDate.Value.Value.AddDays(1);
|
||||
room.Value.StartDate = DateTimeOffset.Now.AddDays(-1).AddMinutes(8);
|
||||
room.Value.EndDate = room.Value.StartDate.Value.AddDays(1);
|
||||
});
|
||||
AddStep("already ended", () =>
|
||||
{
|
||||
room.Value.StartDate.Value = DateTimeOffset.Now.AddDays(-2);
|
||||
room.Value.EndDate.Value = room.Value.StartDate.Value.Value.AddDays(1);
|
||||
room.Value.StartDate = DateTimeOffset.Now.AddDays(-2);
|
||||
room.Value.EndDate = room.Value.StartDate.Value.AddDays(1);
|
||||
});
|
||||
AddSliderStep("manual progress", 0f, 1f, 0f, progress =>
|
||||
{
|
||||
var startedTimeAgo = TimeSpan.FromHours(24) * progress;
|
||||
room.Value.StartDate.Value = DateTimeOffset.Now - startedTimeAgo;
|
||||
room.Value.EndDate.Value = room.Value.StartDate.Value.Value.AddDays(1);
|
||||
room.Value.StartDate = DateTimeOffset.Now - startedTimeAgo;
|
||||
room.Value.EndDate = room.Value.StartDate.Value.AddDays(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Edit;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Components.RadioButtons;
|
||||
using osu.Game.Screens.Edit.Components.TernaryButtons;
|
||||
@@ -82,6 +83,45 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlacementOutsideComposeScreen()
|
||||
{
|
||||
AddStep("clear all control points and hitobjects", () =>
|
||||
{
|
||||
editorBeatmap.ControlPointInfo.Clear();
|
||||
editorBeatmap.Clear();
|
||||
});
|
||||
|
||||
AddStep("Add timing point", () => editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint()));
|
||||
AddStep("select circle", () => hitObjectComposer.ChildrenOfType<EditorRadioButton>().First(d => d.Button.Label == "HitCircle").TriggerClick());
|
||||
AddStep("move mouse to compose", () => InputManager.MoveMouseTo(hitObjectComposer.ChildrenOfType<HitObjectContainer>().Single()));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddAssert("circle placed", () => editorBeatmap.HitObjects.Count == 1);
|
||||
|
||||
AddStep("move mouse outside compose", () => InputManager.MoveMouseTo(hitObjectComposer.ChildrenOfType<HitObjectContainer>().Single().ScreenSpaceDrawQuad.TopLeft - new Vector2(0f, 20f)));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddAssert("no circle placed", () => editorBeatmap.HitObjects.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDragSliderOutsideComposeScreen()
|
||||
{
|
||||
AddStep("clear all control points and hitobjects", () =>
|
||||
{
|
||||
editorBeatmap.ControlPointInfo.Clear();
|
||||
editorBeatmap.Clear();
|
||||
});
|
||||
|
||||
AddStep("Add timing point", () => editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint()));
|
||||
AddStep("select slider", () => hitObjectComposer.ChildrenOfType<EditorRadioButton>().First(d => d.Button.Label == "Slider").TriggerClick());
|
||||
|
||||
AddStep("move mouse to compose", () => InputManager.MoveMouseTo(hitObjectComposer.ChildrenOfType<HitObjectContainer>().Single()));
|
||||
AddStep("hold", () => InputManager.PressButton(MouseButton.Left));
|
||||
AddStep("move mouse outside compose", () => InputManager.MoveMouseTo(hitObjectComposer.ChildrenOfType<HitObjectContainer>().Single().ScreenSpaceDrawQuad.TopLeft - new Vector2(0f, 80f)));
|
||||
AddStep("release", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
AddAssert("slider placed", () => editorBeatmap.HitObjects.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlacementOnlyWorksWithTiming()
|
||||
{
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
using osu.Game.Tests.Resources;
|
||||
@@ -52,6 +56,39 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("No calibration button", () => !offsetControl.ChildrenOfType<SettingsButton>().Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNotEnoughTimedHitEvents()
|
||||
{
|
||||
AddStep("Set short reference score", () =>
|
||||
{
|
||||
List<HitEvent> hitEvents =
|
||||
[
|
||||
// 10 events total. one of them (head circle) being timed / having hitwindows, rest having no hitwindows
|
||||
new HitEvent(30, 1, HitResult.LargeTickHit, new SliderHeadCircle { ClassicSliderBehaviour = true }, null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
new HitEvent(0, 1, HitResult.LargeTickHit, new SliderTick(), null, null),
|
||||
];
|
||||
|
||||
foreach (var ev in hitEvents)
|
||||
ev.HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
|
||||
offsetControl.ReferenceScore.Value = new ScoreInfo
|
||||
{
|
||||
HitEvents = hitEvents,
|
||||
BeatmapInfo = Beatmap.Value.BeatmapInfo,
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("No calibration button", () => !offsetControl.ChildrenOfType<SettingsButton>().Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScoreFromDifferentBeatmap()
|
||||
{
|
||||
|
||||
@@ -523,7 +523,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("restart completed", () => getCurrentPlayer() != null && getCurrentPlayer() != previousPlayer);
|
||||
AddStep("release quick retry key", () => InputManager.ReleaseKey(Key.Tilde));
|
||||
|
||||
AddUntilStep("wait for player", () => getCurrentPlayer()?.LoadState == LoadState.Ready);
|
||||
AddUntilStep("wait for player", () => getCurrentPlayer()?.LoadState >= LoadState.Ready);
|
||||
|
||||
AddUntilStep("time reached zero", () => getCurrentPlayer()?.GameplayClockContainer.CurrentTime > 0);
|
||||
AddUntilStep("skip button not visible", () => !checkSkipButtonVisible());
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
protected partial class OutroPlayer : TestPlayer
|
||||
{
|
||||
public void ExitViaPause() => PerformExit(true);
|
||||
public void ExitViaPause() => PerformExitWithConfirmation();
|
||||
|
||||
public new FailOverlay FailOverlay => base.FailOverlay;
|
||||
|
||||
|
||||
@@ -42,14 +42,14 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
beatmap.OnlineID = 1001;
|
||||
getRoomRequest.TriggerSuccess(new Room
|
||||
{
|
||||
RoomID = { Value = 1234 },
|
||||
Name = { Value = "Aug 8, 2024" },
|
||||
RoomID = 1234,
|
||||
Name = "Aug 8, 2024",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmap)
|
||||
},
|
||||
StartDate = { Value = DateTimeOffset.Now.AddMinutes(-30) },
|
||||
EndDate = { Value = DateTimeOffset.Now.AddSeconds(60) }
|
||||
],
|
||||
StartDate = DateTimeOffset.Now.AddMinutes(-30),
|
||||
EndDate = DateTimeOffset.Now.AddSeconds(60)
|
||||
});
|
||||
return true;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Mods
|
||||
MinimumAccuracy = { Value = 0.6 }
|
||||
},
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = Enumerable.Range(0, 5).Select(i => new HitCircle
|
||||
{
|
||||
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Mods
|
||||
AccuracyJudgeMode = { Value = ModAccuracyChallenge.AccuracyMode.Standard }
|
||||
},
|
||||
Autoplay = false,
|
||||
Beatmap = new Beatmap
|
||||
CreateBeatmap = () => new Beatmap
|
||||
{
|
||||
HitObjects = Enumerable.Range(0, 5).Select(i => new HitCircle
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -30,16 +28,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
protected abstract QueueMode Mode { get; }
|
||||
|
||||
protected BeatmapInfo InitialBeatmap { get; private set; }
|
||||
protected BeatmapInfo OtherBeatmap { get; private set; }
|
||||
protected BeatmapInfo InitialBeatmap { get; private set; } = null!;
|
||||
protected BeatmapInfo OtherBeatmap { get; private set; } = null!;
|
||||
|
||||
protected IScreen CurrentScreen => multiplayerComponents.CurrentScreen;
|
||||
protected IScreen CurrentSubScreen => multiplayerComponents.MultiplayerScreen.CurrentSubScreen;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
private BeatmapSetInfo importedSet;
|
||||
private BeatmapManager beatmaps = null!;
|
||||
private BeatmapSetInfo importedSet = null!;
|
||||
|
||||
private TestMultiplayerComponents multiplayerComponents;
|
||||
private TestMultiplayerComponents multiplayerComponents = null!;
|
||||
|
||||
protected TestMultiplayerClient MultiplayerClient => multiplayerComponents.MultiplayerClient;
|
||||
|
||||
@@ -75,15 +73,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("wait for lounge", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
|
||||
AddStep("open room", () => multiplayerComponents.ChildrenOfType<LoungeSubScreen>().Single().Open(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = Mode },
|
||||
Name = "Test Room",
|
||||
QueueMode = Mode,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(InitialBeatmap)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
||||
@@ -98,7 +96,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestCreatedWithCorrectMode()
|
||||
{
|
||||
AddUntilStep("room created with correct mode", () => MultiplayerClient.ClientAPIRoom?.QueueMode.Value == Mode);
|
||||
AddUntilStep("room created with correct mode", () => MultiplayerClient.ClientAPIRoom?.QueueMode == Mode);
|
||||
}
|
||||
|
||||
protected void RunGameplay()
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -10,6 +8,7 @@ using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Testing;
|
||||
@@ -25,14 +24,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
private readonly Room room = new Room
|
||||
{
|
||||
HasPassword = { Value = true }
|
||||
Password = "*"
|
||||
};
|
||||
|
||||
[Cached]
|
||||
protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||
|
||||
private DrawableLoungeRoom drawableRoom;
|
||||
private SearchTextBox searchTextBox;
|
||||
private DrawableLoungeRoom drawableRoom = null!;
|
||||
private SearchTextBox searchTextBox = null!;
|
||||
|
||||
private readonly ManualResetEventSlim allowResponseCallback = new ManualResetEventSlim();
|
||||
|
||||
@@ -78,6 +77,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
SelectedRoom = new Bindable<Room?>()
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestFocusViaKeyboardCommit()
|
||||
{
|
||||
DrawableLoungeRoom.PasswordEntryPopover popover = null;
|
||||
DrawableLoungeRoom.PasswordEntryPopover? popover = null;
|
||||
|
||||
AddAssert("search textbox has focus", () => checkFocus(searchTextBox));
|
||||
AddStep("click room twice", () =>
|
||||
@@ -103,11 +103,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("enter password", () => popover.ChildrenOfType<OsuPasswordTextBox>().Single().Text = "password");
|
||||
AddStep("commit via enter", () => InputManager.Key(Key.Enter));
|
||||
|
||||
AddAssert("popover has focus", () => checkFocus(popover));
|
||||
AddAssert("popover has focus", () => checkFocus(popover!));
|
||||
|
||||
AddStep("attempt another enter", () => InputManager.Key(Key.Enter));
|
||||
|
||||
AddAssert("popover still has focus", () => checkFocus(popover));
|
||||
AddAssert("popover still has focus", () => checkFocus(popover!));
|
||||
|
||||
AddStep("unblock response", () => allowResponseCallback.Set());
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestFocusViaMouseCommit()
|
||||
{
|
||||
DrawableLoungeRoom.PasswordEntryPopover popover = null;
|
||||
DrawableLoungeRoom.PasswordEntryPopover? popover = null;
|
||||
|
||||
AddAssert("search textbox has focus", () => checkFocus(searchTextBox));
|
||||
AddStep("click room twice", () =>
|
||||
@@ -144,11 +144,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("popover has focus", () => checkFocus(popover));
|
||||
AddAssert("popover has focus", () => checkFocus(popover!));
|
||||
|
||||
AddStep("attempt another click", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
AddAssert("popover still has focus", () => checkFocus(popover));
|
||||
AddAssert("popover still has focus", () => checkFocus(popover!));
|
||||
|
||||
AddStep("unblock response", () => allowResponseCallback.Set());
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
@@ -32,15 +30,40 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Cached]
|
||||
protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||
|
||||
private readonly Bindable<Room> selectedRoom = new Bindable<Room>();
|
||||
private readonly Bindable<Room?> selectedRoom = new Bindable<Room?>();
|
||||
|
||||
[Test]
|
||||
public void TestMultipleStatuses()
|
||||
{
|
||||
FillFlowContainer rooms = null;
|
||||
FillFlowContainer rooms = null!;
|
||||
|
||||
AddStep("create rooms", () =>
|
||||
{
|
||||
PlaylistItem item1 = new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo = { StarRating = 2.5 }
|
||||
}.BeatmapInfo);
|
||||
|
||||
PlaylistItem item2 = new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo = { StarRating = 4.5 }
|
||||
}.BeatmapInfo);
|
||||
|
||||
PlaylistItem item3 = new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
StarRating = 2.5,
|
||||
Metadata =
|
||||
{
|
||||
Artist = "very very very very very very very very very long artist",
|
||||
ArtistUnicode = "very very very very very very very very very long artist",
|
||||
Title = "very very very very very very very very very very very long title",
|
||||
TitleUnicode = "very very very very very very very very very very very long title",
|
||||
}
|
||||
}
|
||||
}.BeatmapInfo);
|
||||
|
||||
Child = rooms = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@@ -52,86 +75,48 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Multiplayer room" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||
Type = { Value = MatchType.HeadToHead },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
StarRating = 2.5
|
||||
}
|
||||
}.BeatmapInfo)
|
||||
}
|
||||
Name = "Multiplayer room",
|
||||
Status = new RoomStatusOpen(),
|
||||
EndDate = DateTimeOffset.Now.AddDays(1),
|
||||
Type = MatchType.HeadToHead,
|
||||
Playlist = [item1],
|
||||
CurrentPlaylistItem = item1
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Private room" },
|
||||
Status = { Value = new RoomStatusOpenPrivate() },
|
||||
HasPassword = { Value = true },
|
||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||
Type = { Value = MatchType.HeadToHead },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
StarRating = 2.5,
|
||||
Metadata =
|
||||
{
|
||||
Artist = "very very very very very very very very very long artist",
|
||||
ArtistUnicode = "very very very very very very very very very long artist",
|
||||
Title = "very very very very very very very very very very very long title",
|
||||
TitleUnicode = "very very very very very very very very very very very long title",
|
||||
}
|
||||
}
|
||||
}.BeatmapInfo)
|
||||
}
|
||||
Name = "Private room",
|
||||
Status = new RoomStatusOpenPrivate(),
|
||||
Password = "*",
|
||||
EndDate = DateTimeOffset.Now.AddDays(1),
|
||||
Type = MatchType.HeadToHead,
|
||||
Playlist = [item3],
|
||||
CurrentPlaylistItem = item3
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Playlist room with multiple beatmaps" },
|
||||
Status = { Value = new RoomStatusPlaying() },
|
||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
StarRating = 2.5
|
||||
}
|
||||
}.BeatmapInfo),
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
StarRating = 4.5
|
||||
}
|
||||
}.BeatmapInfo)
|
||||
}
|
||||
Name = "Playlist room with multiple beatmaps",
|
||||
Status = new RoomStatusPlaying(),
|
||||
EndDate = DateTimeOffset.Now.AddDays(1),
|
||||
Playlist = [item1, item2],
|
||||
CurrentPlaylistItem = item1
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Finished room" },
|
||||
Status = { Value = new RoomStatusEnded() },
|
||||
EndDate = { Value = DateTimeOffset.Now },
|
||||
Name = "Finished room",
|
||||
Status = new RoomStatusEnded(),
|
||||
EndDate = DateTimeOffset.Now,
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Spotlight room" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Category = { Value = RoomCategory.Spotlight },
|
||||
Name = "Spotlight room",
|
||||
Status = new RoomStatusOpen(),
|
||||
Category = RoomCategory.Spotlight,
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Featured artist room" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Category = { Value = RoomCategory.FeaturedArtist },
|
||||
Name = "Featured artist room",
|
||||
Status = new RoomStatusOpen(),
|
||||
Category = RoomCategory.FeaturedArtist,
|
||||
}),
|
||||
}
|
||||
};
|
||||
@@ -145,24 +130,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestEnableAndDisablePassword()
|
||||
{
|
||||
DrawableRoom drawableRoom = null;
|
||||
Room room = null;
|
||||
DrawableRoom drawableRoom = null!;
|
||||
Room room = null!;
|
||||
|
||||
AddStep("create room", () => Child = drawableRoom = createLoungeRoom(room = new Room
|
||||
{
|
||||
Name = { Value = "Room with password" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Type = { Value = MatchType.HeadToHead },
|
||||
Name = "Room with password",
|
||||
Status = new RoomStatusOpen(),
|
||||
Type = MatchType.HeadToHead,
|
||||
}));
|
||||
|
||||
AddUntilStep("wait for panel load", () => drawableRoom.ChildrenOfType<DrawableRoomParticipantsList>().Any());
|
||||
|
||||
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||
|
||||
AddStep("set password", () => room.Password.Value = "password");
|
||||
AddStep("set password", () => room.Password = "password");
|
||||
AddAssert("password icon visible", () => Precision.AlmostEquals(1, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||
|
||||
AddStep("unset password", () => room.Password.Value = string.Empty);
|
||||
AddStep("unset password", () => room.Password = string.Empty);
|
||||
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||
}
|
||||
|
||||
@@ -179,43 +164,52 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
new DrawableMatchRoom(new Room
|
||||
{
|
||||
Name = { Value = "A host-only room" },
|
||||
QueueMode = { Value = QueueMode.HostOnly },
|
||||
Type = { Value = MatchType.HeadToHead }
|
||||
}),
|
||||
Name = "A host-only room",
|
||||
QueueMode = QueueMode.HostOnly,
|
||||
Type = MatchType.HeadToHead,
|
||||
})
|
||||
{
|
||||
SelectedItem = new Bindable<PlaylistItem?>()
|
||||
},
|
||||
new DrawableMatchRoom(new Room
|
||||
{
|
||||
Name = { Value = "An all-players, team-versus room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Type = { Value = MatchType.TeamVersus }
|
||||
}),
|
||||
Name = "An all-players, team-versus room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Type = MatchType.TeamVersus
|
||||
})
|
||||
{
|
||||
SelectedItem = new Bindable<PlaylistItem?>()
|
||||
},
|
||||
new DrawableMatchRoom(new Room
|
||||
{
|
||||
Name = { Value = "A round-robin room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayersRoundRobin },
|
||||
Type = { Value = MatchType.HeadToHead }
|
||||
}),
|
||||
Name = "A round-robin room",
|
||||
QueueMode = QueueMode.AllPlayersRoundRobin,
|
||||
Type = MatchType.HeadToHead
|
||||
})
|
||||
{
|
||||
SelectedItem = new Bindable<PlaylistItem?>()
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DrawableRoom createLoungeRoom(Room room)
|
||||
{
|
||||
room.Host.Value ??= new APIUser { Username = "peppy", Id = 2 };
|
||||
room.Host ??= new APIUser { Username = "peppy", Id = 2 };
|
||||
|
||||
if (room.RecentParticipants.Count == 0)
|
||||
{
|
||||
room.RecentParticipants.AddRange(Enumerable.Range(0, 20).Select(i => new APIUser
|
||||
room.RecentParticipants = Enumerable.Range(0, 20).Select(i => new APIUser
|
||||
{
|
||||
Id = i,
|
||||
Username = $"User {i}"
|
||||
}));
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
return new DrawableLoungeRoom(room)
|
||||
{
|
||||
MatchingFilter = true,
|
||||
SelectedRoom = { BindTarget = selectedRoom }
|
||||
SelectedRoom = selectedRoom
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
@@ -17,7 +15,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public partial class TestSceneDrawableRoomParticipantsList : OnlinePlayTestScene
|
||||
{
|
||||
private DrawableRoomParticipantsList list;
|
||||
private DrawableRoomParticipantsList list = null!;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
@@ -27,18 +25,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
SelectedRoom.Value = new Room
|
||||
{
|
||||
Name = { Value = "test room" },
|
||||
Host =
|
||||
Name = "test room",
|
||||
Host = new APIUser
|
||||
{
|
||||
Value = new APIUser
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
}
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
}
|
||||
};
|
||||
|
||||
Child = list = new DrawableRoomParticipantsList
|
||||
Child = list = new DrawableRoomParticipantsList(SelectedRoom.Value)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@@ -143,18 +138,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
private void addUser(int id)
|
||||
{
|
||||
SelectedRoom.Value.RecentParticipants.Add(new APIUser
|
||||
SelectedRoom.Value.RecentParticipants = SelectedRoom.Value.RecentParticipants.Append(new APIUser
|
||||
{
|
||||
Id = id,
|
||||
Username = $"User {id}"
|
||||
});
|
||||
SelectedRoom.Value.ParticipantCount.Value++;
|
||||
}).ToArray();
|
||||
SelectedRoom.Value.ParticipantCount++;
|
||||
}
|
||||
|
||||
private void removeUserAt(int index)
|
||||
{
|
||||
SelectedRoom.Value.RecentParticipants.RemoveAt(index);
|
||||
SelectedRoom.Value.ParticipantCount.Value--;
|
||||
SelectedRoom.Value.RecentParticipants = SelectedRoom.Value.RecentParticipants.Where(u => !u.Equals(SelectedRoom.Value.RecentParticipants[index])).ToArray();
|
||||
SelectedRoom.Value.ParticipantCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
QueueMode = QueueMode.AllPlayers
|
||||
}).WaitSafely());
|
||||
|
||||
AddUntilStep("api room updated", () => MultiplayerClient.ClientAPIRoom?.QueueMode.Value == QueueMode.AllPlayers);
|
||||
AddUntilStep("api room updated", () => MultiplayerClient.ClientAPIRoom?.QueueMode == QueueMode.AllPlayers);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -55,20 +55,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddAssert("has 5 rooms", () => container.Rooms.Count == 5);
|
||||
|
||||
AddAssert("all spotlights at top", () => container.Rooms
|
||||
.SkipWhile(r => r.Room.Category.Value == RoomCategory.Spotlight)
|
||||
.All(r => r.Room.Category.Value == RoomCategory.Normal));
|
||||
.SkipWhile(r => r.Room.Category == RoomCategory.Spotlight)
|
||||
.All(r => r.Room.Category == RoomCategory.Normal));
|
||||
|
||||
AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.First(r => r.RoomID.Value == 0)));
|
||||
AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.First(r => r.RoomID == 0)));
|
||||
AddAssert("has 4 rooms", () => container.Rooms.Count == 4);
|
||||
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
|
||||
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID != 0));
|
||||
|
||||
AddStep("select first room", () => container.Rooms.First().TriggerClick());
|
||||
AddAssert("first spotlight selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category.Value == RoomCategory.Spotlight)));
|
||||
AddAssert("first spotlight selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category == RoomCategory.Spotlight)));
|
||||
|
||||
AddStep("remove last room", () => RoomManager.RemoveRoom(RoomManager.Rooms.MinBy(r => r.RoomID?.Value)));
|
||||
AddAssert("first spotlight still selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category.Value == RoomCategory.Spotlight)));
|
||||
AddStep("remove last room", () => RoomManager.RemoveRoom(RoomManager.Rooms.MinBy(r => r.RoomID)));
|
||||
AddAssert("first spotlight still selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category == RoomCategory.Spotlight)));
|
||||
|
||||
AddStep("remove spotlight room", () => RoomManager.RemoveRoom(RoomManager.Rooms.Single(r => r.Category.Value == RoomCategory.Spotlight)));
|
||||
AddStep("remove spotlight room", () => RoomManager.RemoveRoom(RoomManager.Rooms.Single(r => r.Category == RoomCategory.Spotlight)));
|
||||
AddAssert("selection vacated", () => checkRoomSelected(null));
|
||||
}
|
||||
|
||||
@@ -182,11 +182,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("filter public rooms", () => container.Filter.Value = new FilterCriteria { Permissions = RoomPermissionsFilter.Public });
|
||||
|
||||
AddUntilStep("private room hidden", () => container.Rooms.All(r => !r.Room.HasPassword.Value));
|
||||
AddUntilStep("private room hidden", () => container.Rooms.All(r => !r.Room.HasPassword));
|
||||
|
||||
AddStep("filter private rooms", () => container.Filter.Value = new FilterCriteria { Permissions = RoomPermissionsFilter.Private });
|
||||
|
||||
AddUntilStep("public room hidden", () => container.Rooms.All(r => r.Room.HasPassword.Value));
|
||||
AddUntilStep("public room hidden", () => container.Rooms.All(r => r.Room.HasPassword));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Rooms;
|
||||
@@ -23,7 +24,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
SelectedRoom.Value = new Room();
|
||||
|
||||
Child = new MatchBeatmapDetailArea
|
||||
Child = new MatchBeatmapDetailArea(SelectedRoom.Value)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
@@ -35,7 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
private void createNewItem()
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
SelectedRoom.Value.Playlist = SelectedRoom.Value.Playlist.Append(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
ID = SelectedRoom.Value.Playlist.Count,
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
@@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
new APIMod(new OsuModDoubleTime()),
|
||||
new APIMod(new OsuModAutoplay())
|
||||
}
|
||||
});
|
||||
}).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +61,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("create leaderboard", () =>
|
||||
{
|
||||
SelectedRoom.Value = new Room { RoomID = { Value = 3 } };
|
||||
SelectedRoom.Value = new Room { RoomID = 3 };
|
||||
|
||||
Child = new MatchLeaderboard
|
||||
Child = new MatchLeaderboard(SelectedRoom.Value)
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
|
||||
@@ -43,12 +43,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
private OsuButton readyButton => control.ChildrenOfType<OsuButton>().Single();
|
||||
|
||||
[Cached(typeof(IBindable<PlaylistItem>))]
|
||||
private readonly Bindable<PlaylistItem> currentItem = new Bindable<PlaylistItem>();
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
|
||||
new CachedModelDependencyContainer<Room>(base.CreateChildDependencies(parent)) { Model = { BindTarget = room } };
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@@ -107,31 +101,33 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
PlaylistItem item = null!;
|
||||
|
||||
AddStep("reset state", () =>
|
||||
{
|
||||
multiplayerClient.Invocations.Clear();
|
||||
|
||||
beatmapAvailability.Value = BeatmapAvailability.LocallyAvailable();
|
||||
|
||||
currentItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
||||
item = new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
||||
{
|
||||
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID
|
||||
};
|
||||
|
||||
room.Value = new Room
|
||||
{
|
||||
Playlist = { currentItem.Value },
|
||||
CurrentPlaylistItem = { BindTarget = currentItem }
|
||||
Playlist = [item],
|
||||
CurrentPlaylistItem = item
|
||||
};
|
||||
|
||||
localUser = new MultiplayerRoomUser(API.LocalUser.Value.Id) { User = API.LocalUser.Value };
|
||||
localUser = new MultiplayerRoomUser(API.LocalUser.Value.Id)
|
||||
{
|
||||
User = API.LocalUser.Value
|
||||
};
|
||||
|
||||
multiplayerRoom = new MultiplayerRoom(0)
|
||||
{
|
||||
Playlist =
|
||||
{
|
||||
TestMultiplayerClient.CreateMultiplayerPlaylistItem(currentItem.Value),
|
||||
},
|
||||
Playlist = { TestMultiplayerClient.CreateMultiplayerPlaylistItem(item) },
|
||||
Users = { localUser },
|
||||
Host = localUser,
|
||||
};
|
||||
@@ -144,6 +140,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(250, 50),
|
||||
SelectedItem = new Bindable<PlaylistItem?>(item)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,14 +103,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddRepeatStep("random stuff happens", performRandomAction, 30);
|
||||
@@ -238,17 +238,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddUntilStep("Check participant count correct", () => multiplayerClient.ClientAPIRoom?.ParticipantCount.Value == 1);
|
||||
AddUntilStep("Check participant count correct", () => multiplayerClient.ClientAPIRoom?.ParticipantCount == 1);
|
||||
AddUntilStep("Check participant list contains user", () => multiplayerClient.ClientAPIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
|
||||
}
|
||||
|
||||
@@ -259,14 +259,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
roomManager.AddServerSideRoom(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
}, API.LocalUser.Value);
|
||||
});
|
||||
|
||||
@@ -288,14 +288,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
roomManager.AddServerSideRoom(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
}, API.LocalUser.Value);
|
||||
});
|
||||
|
||||
@@ -308,7 +308,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
||||
AddUntilStep("wait for join", () => multiplayerClient.RoomJoined);
|
||||
|
||||
AddUntilStep("Check participant count correct", () => multiplayerClient.ClientAPIRoom?.ParticipantCount.Value == 1);
|
||||
AddUntilStep("Check participant count correct", () => multiplayerClient.ClientAPIRoom?.ParticipantCount == 1);
|
||||
AddUntilStep("Check participant list contains user", () => multiplayerClient.ClientAPIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
|
||||
}
|
||||
|
||||
@@ -317,18 +317,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Password = { Value = "password" },
|
||||
Name = "Test Room",
|
||||
Password = "password",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddUntilStep("room has password", () => multiplayerClient.ClientAPIRoom?.Password.Value == "password");
|
||||
AddUntilStep("room has password", () => multiplayerClient.ClientAPIRoom?.Password == "password");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -338,15 +338,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
roomManager.AddServerSideRoom(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Password = { Value = "password" },
|
||||
Name = "Test Room",
|
||||
Password = "password",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
}, API.LocalUser.Value);
|
||||
});
|
||||
|
||||
@@ -370,19 +370,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Password = { Value = "password" },
|
||||
Name = "Test Room",
|
||||
Password = "password",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("change password", () => multiplayerClient.ChangeSettings(password: "password2"));
|
||||
AddUntilStep("local password changed", () => multiplayerClient.ClientAPIRoom?.Password.Value == "password2");
|
||||
AddUntilStep("local password changed", () => multiplayerClient.ClientAPIRoom?.Password == "password2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -401,14 +401,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
pressReadyButton();
|
||||
@@ -430,8 +430,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
};
|
||||
return new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Playlist = { item }
|
||||
Name = "Test Room",
|
||||
Playlist = [item]
|
||||
};
|
||||
});
|
||||
|
||||
@@ -471,8 +471,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
};
|
||||
return new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Playlist = { item }
|
||||
Name = "Test Room",
|
||||
Playlist = [item]
|
||||
};
|
||||
});
|
||||
|
||||
@@ -512,8 +512,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
};
|
||||
return new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Playlist = { item }
|
||||
Name = "Test Room",
|
||||
Playlist = [item]
|
||||
};
|
||||
});
|
||||
|
||||
@@ -548,14 +548,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("join other user (ready, host)", () =>
|
||||
@@ -581,14 +581,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
|
||||
@@ -620,14 +620,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("disconnect", () => multiplayerClient.Disconnect());
|
||||
@@ -639,15 +639,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new OsuModHidden()) }
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("open mod overlay", () => this.ChildrenOfType<UserModSelectButton>().Single().TriggerClick());
|
||||
@@ -679,14 +679,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
enterGameplay();
|
||||
@@ -724,14 +724,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
enterGameplay();
|
||||
@@ -754,14 +754,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
pressReadyButton();
|
||||
@@ -791,15 +791,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
roomManager.AddServerSideRoom(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Name = "Test Room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
}, API.LocalUser.Value);
|
||||
});
|
||||
|
||||
@@ -810,12 +810,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("disable polling", () => this.ChildrenOfType<ListingPollingComponent>().Single().TimeBetweenPolls.Value = 0);
|
||||
AddStep("change server-side settings", () =>
|
||||
{
|
||||
roomManager.ServerSideRooms[0].Name.Value = "New name";
|
||||
roomManager.ServerSideRooms[0].Playlist.Add(new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
ID = 2,
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
});
|
||||
roomManager.ServerSideRooms[0].Name = "New name";
|
||||
roomManager.ServerSideRooms[0].Playlist =
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
ID = 2,
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
AddStep("join room", () => InputManager.Key(Key.Enter));
|
||||
@@ -825,8 +828,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddAssert("local room has correct settings", () =>
|
||||
{
|
||||
var localRoom = this.ChildrenOfType<MultiplayerMatchSubScreen>().Single().Room;
|
||||
return localRoom.Name.Value == roomManager.ServerSideRooms[0].Name.Value
|
||||
&& localRoom.Playlist.SequenceEqual(roomManager.ServerSideRooms[0].Playlist);
|
||||
return localRoom.Name == roomManager.ServerSideRooms[0].Name && localRoom.Playlist.Single().ID == 2;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -836,15 +838,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Name = "Test Room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("set spectating state", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
|
||||
@@ -872,15 +874,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Name = "Test Room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("set spectating state", () => multiplayerClient.ChangeUserState(API.LocalUser.Value.OnlineID, MultiplayerUserState.Spectating));
|
||||
@@ -911,15 +913,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Name = "Test Room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
enterGameplay();
|
||||
@@ -942,15 +944,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Name = "Test Room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
enterGameplay();
|
||||
@@ -976,14 +978,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Name = "Test Room",
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("join other user and make host", () =>
|
||||
@@ -1022,10 +1024,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
QueueMode = { Value = QueueMode.AllPlayers },
|
||||
Name = "Test Room",
|
||||
QueueMode = QueueMode.AllPlayers,
|
||||
Playlist =
|
||||
{
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
@@ -1036,7 +1038,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod { Acronym = "HD" } },
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
AddStep("select hidden", () => multiplayerClient.ChangeUserMods(new[] { new APIMod { Acronym = "HD" } }));
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@@ -13,9 +12,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public partial class TestSceneMultiplayerMatchFooter : MultiplayerTestScene
|
||||
{
|
||||
[Cached(typeof(IBindable<PlaylistItem>))]
|
||||
private readonly Bindable<PlaylistItem> currentItem = new Bindable<PlaylistItem>();
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
@@ -33,7 +29,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 50,
|
||||
Child = new MultiplayerMatchFooter()
|
||||
Child = new MultiplayerMatchFooter
|
||||
{
|
||||
SelectedItem = new Bindable<PlaylistItem?>()
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
AddStep("load match", () =>
|
||||
{
|
||||
SelectedRoom.Value = new Room { Name = { Value = "Test Room" } };
|
||||
SelectedRoom.Value = new Room { Name = "Test Room" };
|
||||
LoadScreen(screen = new TestMultiplayerMatchSubScreen(SelectedRoom.Value));
|
||||
});
|
||||
|
||||
@@ -77,33 +77,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest]
|
||||
/*
|
||||
* Fail rate around 1.5%
|
||||
*
|
||||
* TearDown : System.AggregateException : One or more errors occurred. (Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index'))
|
||||
----> System.ArgumentOutOfRangeException : Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
|
||||
* --TearDown
|
||||
* at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
|
||||
* at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
|
||||
* at osu.Framework.Extensions.TaskExtensions.WaitSafely(Task task)
|
||||
* at osu.Framework.Testing.TestScene.checkForErrors()
|
||||
* at osu.Framework.Testing.TestScene.RunTestsFromNUnit()
|
||||
*--ArgumentOutOfRangeException
|
||||
* at osu.Framework.Bindables.BindableList`1.removeAt(Int32 index, BindableList`1 caller)
|
||||
* at osu.Framework.Bindables.BindableList`1.removeAt(Int32 index, BindableList`1 caller)
|
||||
* at osu.Framework.Bindables.BindableList`1.removeAt(Int32 index, BindableList`1 caller)
|
||||
* at osu.Game.Online.Multiplayer.MultiplayerClient.<>c__DisplayClass106_0.<PlaylistItemChanged>b__0() in C:\BuildAgent\work\ecd860037212ac52\osu.Game\Online\Multiplayer\MultiplayerClient .cs:line 702
|
||||
* at osu.Framework.Threading.ScheduledDelegate.RunTaskInternal()
|
||||
*/
|
||||
public void TestCreatedRoom()
|
||||
{
|
||||
AddStep("add playlist item", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
@@ -112,16 +96,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestTaikoOnlyMod()
|
||||
{
|
||||
AddStep("add playlist item", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new TaikoModSwap()) }
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new TaikoRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new TaikoModSwap()) }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
@@ -133,32 +119,36 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestSettingValidity()
|
||||
{
|
||||
AddAssert("create button not enabled", () => !this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("set playlist", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestStartMatchWhileSpectating()
|
||||
{
|
||||
AddStep("set playlist", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
@@ -179,16 +169,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestFreeModSelectionHasAllowedMods()
|
||||
{
|
||||
AddStep("add playlist item with allowed mod", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
@@ -206,16 +198,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestModSelectKeyWithAllowedMods()
|
||||
{
|
||||
AddStep("add playlist item with allowed mod", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
AllowedMods = new[] { new APIMod(new OsuModDoubleTime()) }
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
@@ -228,15 +222,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestModSelectKeyWithNoAllowedMods()
|
||||
{
|
||||
AddStep("add playlist item with no allowed mods", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
});
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
}
|
||||
];
|
||||
});
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
|
||||
@@ -249,13 +245,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestNextPlaylistItemSelectedAfterCompletion()
|
||||
{
|
||||
AddStep("add two playlist items", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.AddRange(new[]
|
||||
{
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First()).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
@@ -264,7 +259,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID
|
||||
}
|
||||
});
|
||||
];
|
||||
});
|
||||
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
@@ -286,24 +281,26 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
[FlakyTest] // See above
|
||||
public void TestModSelectOverlay()
|
||||
{
|
||||
AddStep("add playlist item", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
RequiredMods = new[]
|
||||
SelectedRoom.Value.Playlist =
|
||||
[
|
||||
new PlaylistItem(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo)
|
||||
{
|
||||
new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 2.0 } }),
|
||||
new APIMod(new OsuModStrictTracking()),
|
||||
},
|
||||
AllowedMods = new[]
|
||||
{
|
||||
new APIMod(new OsuModFlashlight()),
|
||||
RulesetID = new OsuRuleset().RulesetInfo.OnlineID,
|
||||
RequiredMods = new[]
|
||||
{
|
||||
new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 2.0 } }),
|
||||
new APIMod(new OsuModStrictTracking()),
|
||||
},
|
||||
AllowedMods = new[]
|
||||
{
|
||||
new APIMod(new OsuModFlashlight()),
|
||||
}
|
||||
}
|
||||
});
|
||||
];
|
||||
});
|
||||
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// 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.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -22,7 +20,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public partial class TestSceneMultiplayerPlayer : MultiplayerTestScene
|
||||
{
|
||||
private MultiplayerPlayer player;
|
||||
private MultiplayerPlayer player = null!;
|
||||
|
||||
[Test]
|
||||
public void TestGameplay()
|
||||
@@ -49,7 +47,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("score changed", () => player.GameplayState.ScoreProcessor.TotalScore.Value > 0);
|
||||
}
|
||||
|
||||
private void setup(Func<IReadOnlyList<Mod>> mods = null)
|
||||
private void setup(Func<IReadOnlyList<Mod>>? mods = null)
|
||||
{
|
||||
AddStep("set beatmap", () =>
|
||||
{
|
||||
@@ -64,10 +62,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("initialise gameplay", () =>
|
||||
{
|
||||
Stack.Push(player = new MultiplayerPlayer(MultiplayerClient.ServerAPIRoom, new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
||||
Stack.Push(player = new MultiplayerPlayer(MultiplayerClient.ServerAPIRoom!, new PlaylistItem(Beatmap.Value.BeatmapInfo)
|
||||
{
|
||||
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
|
||||
}, MultiplayerClient.ServerRoom?.Users.ToArray()));
|
||||
}, MultiplayerClient.ServerRoom!.Users.ToArray()));
|
||||
});
|
||||
|
||||
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen() && player.IsLoaded);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user