mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 16:12:54 +08:00
Merge remote-tracking branch 'upstream/master' into fix-remaining-identifier-names
This commit is contained in:
commit
b245ffefc1
@ -13,3 +13,5 @@ M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.H
|
||||
M:Realms.IRealmCollection`1.SubscribeForNotifications`1(Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IRealmCollection<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IQueryable<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IList<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks.
|
||||
P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks.
|
||||
|
@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi
|
||||
|
||||
**Latest build:**
|
||||
|
||||
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.15+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| ------------- | ------------- | ------------- | ------------- | ------------- |
|
||||
|
||||
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
|
||||
|
@ -51,8 +51,8 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1215.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.109.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.111.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -14,7 +14,6 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(10000)]
|
||||
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
|
||||
|
@ -52,16 +52,25 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HandleFlip(Direction direction)
|
||||
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
|
||||
{
|
||||
if (SelectedItems.Count == 0)
|
||||
return false;
|
||||
|
||||
// This could be implemented in the future if there's a requirement for it.
|
||||
if (direction == Direction.Vertical)
|
||||
return false;
|
||||
|
||||
var selectionRange = CatchHitObjectUtils.GetPositionRange(SelectedItems);
|
||||
|
||||
bool changed = false;
|
||||
|
||||
EditorBeatmap.PerformOnSelection(h =>
|
||||
{
|
||||
if (h is CatchHitObject catchObject)
|
||||
changed |= handleFlip(selectionRange, catchObject);
|
||||
changed |= handleFlip(selectionRange, catchObject, flipOverOrigin);
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@ -116,7 +125,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return Math.Clamp(deltaX, lowerBound, upperBound);
|
||||
}
|
||||
|
||||
private bool handleFlip(PositionRange selectionRange, CatchHitObject hitObject)
|
||||
private bool handleFlip(PositionRange selectionRange, CatchHitObject hitObject, bool flipOverOrigin)
|
||||
{
|
||||
switch (hitObject)
|
||||
{
|
||||
@ -124,7 +133,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return false;
|
||||
|
||||
case JuiceStream juiceStream:
|
||||
juiceStream.OriginalX = selectionRange.GetFlippedPosition(juiceStream.OriginalX);
|
||||
juiceStream.OriginalX = getFlippedPosition(juiceStream.OriginalX);
|
||||
|
||||
foreach (var point in juiceStream.Path.ControlPoints)
|
||||
point.Position *= new Vector2(-1, 1);
|
||||
@ -133,9 +142,11 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
return true;
|
||||
|
||||
default:
|
||||
hitObject.OriginalX = selectionRange.GetFlippedPosition(hitObject.OriginalX);
|
||||
hitObject.OriginalX = getFlippedPosition(hitObject.OriginalX);
|
||||
return true;
|
||||
}
|
||||
|
||||
float getFlippedPosition(float original) => flipOverOrigin ? CatchPlayfield.WIDTH - original : selectionRange.GetFlippedPosition(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(10000)]
|
||||
public class ManiaBeatmapConversionTest : BeatmapConversionTest<ManiaConvertMapping, ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Mania";
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
||||
|
||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
|
||||
|
||||
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new DrainingHealthProcessor(drainStartTime, 0.5);
|
||||
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new ManiaHealthProcessor(drainStartTime, 0.5);
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||
|
||||
|
23
osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
Normal file
23
osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Scoring
|
||||
{
|
||||
public class ManiaHealthProcessor : DrainingHealthProcessor
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ManiaHealthProcessor(double drainStartTime, double drainLenience = 0)
|
||||
: base(drainStartTime, drainLenience)
|
||||
{
|
||||
}
|
||||
|
||||
protected override HitResult GetSimulatedHitResult(Judgement judgement)
|
||||
{
|
||||
// Users are not expected to attain perfect judgements for all notes due to the tighter hit window.
|
||||
return judgement.MaxResult == HitResult.Perfect ? HitResult.Great : judgement.MaxResult;
|
||||
}
|
||||
}
|
||||
}
|
225
osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs
Normal file
225
osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs
Normal file
@ -0,0 +1,225 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.Edit;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
{
|
||||
public class TestSceneSliderSnapping : EditorTestScene
|
||||
{
|
||||
private const double beat_length = 1000;
|
||||
|
||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var controlPointInfo = new ControlPointInfo();
|
||||
controlPointInfo.Add(0, new TimingControlPoint { BeatLength = beat_length });
|
||||
return new TestBeatmap(ruleset, false)
|
||||
{
|
||||
ControlPointInfo = controlPointInfo
|
||||
};
|
||||
}
|
||||
|
||||
private Slider slider;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("add unsnapped slider", () => EditorBeatmap.Add(slider = new Slider
|
||||
{
|
||||
StartTime = 0,
|
||||
Position = OsuPlayfield.BASE_SIZE / 5,
|
||||
Path = new SliderPath
|
||||
{
|
||||
ControlPoints =
|
||||
{
|
||||
new PathControlPoint(Vector2.Zero),
|
||||
new PathControlPoint(OsuPlayfield.BASE_SIZE * 2 / 5),
|
||||
new PathControlPoint(OsuPlayfield.BASE_SIZE * 3 / 5)
|
||||
}
|
||||
}
|
||||
}));
|
||||
AddStep("set beat divisor to 1/1", () =>
|
||||
{
|
||||
var beatDivisor = (BindableBeatDivisor)Editor.Dependencies.Get(typeof(BindableBeatDivisor));
|
||||
beatDivisor.Value = 1;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMovingUnsnappedSliderNodesSnaps()
|
||||
{
|
||||
PathControlPointPiece sliderEnd = null;
|
||||
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("select slider end", () =>
|
||||
{
|
||||
sliderEnd = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints.Last());
|
||||
InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre);
|
||||
});
|
||||
AddStep("move slider end", () =>
|
||||
{
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.MoveMouseTo(sliderEnd.ScreenSpaceDrawQuad.Centre - new Vector2(0, 20));
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
assertSliderSnapped(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddingControlPointToUnsnappedSliderNodesSnaps()
|
||||
{
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("move mouse to new point location", () =>
|
||||
{
|
||||
var firstPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[0]);
|
||||
var secondPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]);
|
||||
InputManager.MoveMouseTo((firstPiece.ScreenSpaceDrawQuad.Centre + secondPiece.ScreenSpaceDrawQuad.Centre) / 2);
|
||||
});
|
||||
AddStep("move slider end", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
assertSliderSnapped(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRemovingControlPointFromUnsnappedSliderNodesSnaps()
|
||||
{
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("move mouse to second control point", () =>
|
||||
{
|
||||
var secondPiece = this.ChildrenOfType<PathControlPointPiece>().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]);
|
||||
InputManager.MoveMouseTo(secondPiece);
|
||||
});
|
||||
AddStep("quick delete", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ShiftLeft);
|
||||
InputManager.PressButton(MouseButton.Right);
|
||||
InputManager.ReleaseKey(Key.ShiftLeft);
|
||||
});
|
||||
assertSliderSnapped(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestResizingUnsnappedSliderSnaps()
|
||||
{
|
||||
SelectionBoxScaleHandle handle = null;
|
||||
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("move mouse to scale handle", () =>
|
||||
{
|
||||
handle = this.ChildrenOfType<SelectionBoxScaleHandle>().First();
|
||||
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
||||
});
|
||||
AddStep("scale slider", () =>
|
||||
{
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre + new Vector2(20, 20));
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
assertSliderSnapped(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRotatingUnsnappedSliderDoesNotSnap()
|
||||
{
|
||||
SelectionBoxRotationHandle handle = null;
|
||||
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("move mouse to rotate handle", () =>
|
||||
{
|
||||
handle = this.ChildrenOfType<SelectionBoxRotationHandle>().First();
|
||||
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
|
||||
});
|
||||
AddStep("scale slider", () =>
|
||||
{
|
||||
InputManager.PressButton(MouseButton.Left);
|
||||
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre + new Vector2(0, 20));
|
||||
InputManager.ReleaseButton(MouseButton.Left);
|
||||
});
|
||||
assertSliderSnapped(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFlippingSliderDoesNotSnap()
|
||||
{
|
||||
OsuSelectionHandler selectionHandler = null;
|
||||
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("flip slider horizontally", () =>
|
||||
{
|
||||
selectionHandler = this.ChildrenOfType<OsuSelectionHandler>().Single();
|
||||
selectionHandler.OnPressed(new KeyBindingPressEvent<GlobalAction>(InputManager.CurrentState, GlobalAction.EditorFlipHorizontally));
|
||||
});
|
||||
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("flip slider vertically", () =>
|
||||
{
|
||||
selectionHandler = this.ChildrenOfType<OsuSelectionHandler>().Single();
|
||||
selectionHandler.OnPressed(new KeyBindingPressEvent<GlobalAction>(InputManager.CurrentState, GlobalAction.EditorFlipVertically));
|
||||
});
|
||||
|
||||
assertSliderSnapped(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReversingSliderDoesNotSnap()
|
||||
{
|
||||
assertSliderSnapped(false);
|
||||
|
||||
AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider));
|
||||
AddStep("reverse slider", () =>
|
||||
{
|
||||
InputManager.PressKey(Key.ControlLeft);
|
||||
InputManager.Key(Key.G);
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
|
||||
assertSliderSnapped(false);
|
||||
}
|
||||
|
||||
private void assertSliderSnapped(bool snapped)
|
||||
=> AddAssert($"slider is {(snapped ? "" : "not ")}snapped", () =>
|
||||
{
|
||||
double durationInBeatLengths = slider.Duration / beat_length;
|
||||
double fractionalPart = durationInBeatLengths - (int)durationInBeatLengths;
|
||||
return Precision.AlmostEquals(fractionalPart, 0) == snapped;
|
||||
});
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(10000)]
|
||||
public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
BIN
osu.Game.Rulesets.Osu.Tests/Resources/special-skin/hitcircleoverlay-1@2x.png
Executable file
BIN
osu.Game.Rulesets.Osu.Tests/Resources/special-skin/hitcircleoverlay-1@2x.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
if (mods.Any(m => m is OsuModNoFail))
|
||||
multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount);
|
||||
|
||||
if (mods.Any(m => m is OsuModSpunOut))
|
||||
if (mods.Any(m => m is OsuModSpunOut) && totalHits > 0)
|
||||
multiplier *= 1.0 - Math.Pow((double)Attributes.SpinnerCount / totalHits, 0.85);
|
||||
|
||||
if (mods.Any(h => h is OsuModRelax))
|
||||
|
@ -283,6 +283,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
}
|
||||
}
|
||||
|
||||
// Snap the path to the current beat divisor before checking length validity.
|
||||
slider.SnapTo(snapProvider);
|
||||
|
||||
if (!slider.Path.HasValidLength)
|
||||
{
|
||||
for (int i = 0; i < slider.Path.ControlPoints.Count; i++)
|
||||
@ -290,6 +293,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
slider.Position = oldPosition;
|
||||
slider.StartTime = oldStartTime;
|
||||
// Snap the path length again to undo the invalid length.
|
||||
slider.SnapTo(snapProvider);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
controlPoints.BindTo(HitObject.Path.ControlPoints);
|
||||
|
||||
pathVersion.BindTo(HitObject.Path.Version);
|
||||
pathVersion.BindValueChanged(_ => updatePath());
|
||||
pathVersion.BindValueChanged(_ => editorBeatmap?.Update(HitObject));
|
||||
|
||||
BodyPiece.UpdateFrom(HitObject);
|
||||
}
|
||||
@ -208,6 +208,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
// Move the control points from the insertion index onwards to make room for the insertion
|
||||
controlPoints.Insert(insertionIndex, pathControlPoint);
|
||||
|
||||
HitObject.SnapTo(composer);
|
||||
|
||||
return pathControlPoint;
|
||||
}
|
||||
|
||||
@ -227,7 +229,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
controlPoints.Remove(c);
|
||||
}
|
||||
|
||||
// If there are 0 or 1 remaining control points, the slider is in a degenerate (single point) form and should be deleted
|
||||
// Snap the slider to the current beat divisor before checking length validity.
|
||||
HitObject.SnapTo(composer);
|
||||
|
||||
// If there are 0 or 1 remaining control points, or the slider has an invalid length, it is in a degenerate form and should be deleted
|
||||
if (controlPoints.Count <= 1 || !HitObject.Path.HasValidLength)
|
||||
{
|
||||
placementHandler?.Delete(HitObject);
|
||||
@ -242,12 +247,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
HitObject.Position += first;
|
||||
}
|
||||
|
||||
private void updatePath()
|
||||
{
|
||||
HitObject.Path.ExpectedDistance.Value = composer?.GetSnappedDistanceFromDistance(HitObject, (float)HitObject.Path.CalculatedDistance) ?? (float)HitObject.Path.CalculatedDistance;
|
||||
editorBeatmap?.Update(HitObject);
|
||||
}
|
||||
|
||||
private void convertToStream()
|
||||
{
|
||||
if (editorBeatmap == null || changeHandler == null || beatDivisor == null)
|
||||
|
@ -1,15 +1,20 @@
|
||||
// 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 enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osuTK;
|
||||
|
||||
@ -17,6 +22,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
public class OsuSelectionHandler : EditorSelectionHandler
|
||||
{
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPositionSnapProvider? positionSnapProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// During a transform, the initial origin is stored so it can be used throughout the operation.
|
||||
/// </summary>
|
||||
@ -26,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
/// During a transform, the initial path types of a single selected slider are stored so they
|
||||
/// can be maintained throughout the operation.
|
||||
/// </summary>
|
||||
private List<PathType?> referencePathTypes;
|
||||
private List<PathType?>? referencePathTypes;
|
||||
|
||||
protected override void OnSelectionChanged()
|
||||
{
|
||||
@ -84,18 +92,28 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HandleFlip(Direction direction)
|
||||
public override bool HandleFlip(Direction direction, bool flipOverOrigin)
|
||||
{
|
||||
var hitObjects = selectedMovableObjects;
|
||||
|
||||
var selectedObjectsQuad = getSurroundingQuad(hitObjects);
|
||||
var flipQuad = flipOverOrigin ? new Quad(0, 0, OsuPlayfield.BASE_SIZE.X, OsuPlayfield.BASE_SIZE.Y) : getSurroundingQuad(hitObjects);
|
||||
|
||||
bool didFlip = false;
|
||||
|
||||
foreach (var h in hitObjects)
|
||||
{
|
||||
h.Position = GetFlippedPosition(direction, selectedObjectsQuad, h.Position);
|
||||
var flippedPosition = GetFlippedPosition(direction, flipQuad, h.Position);
|
||||
|
||||
if (!Precision.AlmostEquals(flippedPosition, h.Position))
|
||||
{
|
||||
h.Position = flippedPosition;
|
||||
didFlip = true;
|
||||
}
|
||||
|
||||
if (h is Slider slider)
|
||||
{
|
||||
didFlip = true;
|
||||
|
||||
foreach (var point in slider.Path.ControlPoints)
|
||||
{
|
||||
point.Position = new Vector2(
|
||||
@ -106,7 +124,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return didFlip;
|
||||
}
|
||||
|
||||
public override bool HandleScale(Vector2 scale, Anchor reference)
|
||||
@ -186,6 +204,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
for (int i = 0; i < slider.Path.ControlPoints.Count; ++i)
|
||||
slider.Path.ControlPoints[i].Type = referencePathTypes[i];
|
||||
|
||||
// Snap the slider's length to the current beat divisor
|
||||
// to calculate the final resulting duration / bounding box before the final checks.
|
||||
slider.SnapTo(positionSnapProvider);
|
||||
|
||||
//if sliderhead or sliderend end up outside playfield, revert scaling.
|
||||
Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider });
|
||||
(bool xInBounds, bool yInBounds) = isQuadInBounds(scaledQuad);
|
||||
@ -195,6 +217,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
foreach (var point in slider.Path.ControlPoints)
|
||||
point.Position = oldControlPoints.Dequeue();
|
||||
|
||||
// Snap the slider's length again to undo the potentially-invalid length applied by the previous snap.
|
||||
slider.SnapTo(positionSnapProvider);
|
||||
}
|
||||
|
||||
private void scaleHitObjects(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale)
|
||||
|
@ -0,0 +1,52 @@
|
||||
// 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.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
internal class KiaiFlashingDrawable : BeatSyncedContainer
|
||||
{
|
||||
private readonly Drawable flashingDrawable;
|
||||
|
||||
private const float flash_opacity = 0.3f;
|
||||
|
||||
public KiaiFlashingDrawable(Func<Drawable?> creationFunc)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
(creationFunc.Invoke() ?? Empty()).With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.Centre;
|
||||
d.Origin = Anchor.Centre;
|
||||
}),
|
||||
flashingDrawable = (creationFunc.Invoke() ?? Empty()).With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.Centre;
|
||||
d.Origin = Anchor.Centre;
|
||||
d.Alpha = 0;
|
||||
d.Blending = BlendingParameters.Additive;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
if (!effectPoint.KiaiMode)
|
||||
return;
|
||||
|
||||
flashingDrawable
|
||||
.FadeTo(flash_opacity)
|
||||
.Then()
|
||||
.FadeOut(timingPoint.BeatLength * 0.75f);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
// 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.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
internal class KiaiFlashingSprite : BeatSyncedContainer
|
||||
{
|
||||
private readonly Sprite mainSprite;
|
||||
private readonly Sprite flashingSprite;
|
||||
|
||||
public Texture Texture
|
||||
{
|
||||
set
|
||||
{
|
||||
mainSprite.Texture = value;
|
||||
flashingSprite.Texture = value;
|
||||
}
|
||||
}
|
||||
|
||||
private const float flash_opacity = 0.3f;
|
||||
|
||||
public KiaiFlashingSprite()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
mainSprite = new Sprite
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
flashingSprite = new Sprite
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
Blending = BlendingParameters.Additive,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
|
||||
{
|
||||
if (!effectPoint.KiaiMode)
|
||||
return;
|
||||
|
||||
flashingSprite
|
||||
.FadeTo(flash_opacity)
|
||||
.Then()
|
||||
.FadeOut(timingPoint.BeatLength * 0.75f);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -68,13 +69,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
|
||||
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
|
||||
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
|
||||
Texture overlayTexture = getTextureWithFallback("overlay");
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
hitCircleSprite = new KiaiFlashingSprite
|
||||
hitCircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = baseTexture })
|
||||
{
|
||||
Texture = baseTexture,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
@ -82,9 +81,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Child = hitCircleOverlay = new KiaiFlashingSprite
|
||||
Child = hitCircleOverlay = new KiaiFlashingDrawable(() => getAnimationWithFallback(@"overlay", 1000 / 2d))
|
||||
{
|
||||
Texture = overlayTexture,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
@ -126,6 +124,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
|
||||
return tex ?? skin.GetTexture($"hitcircle{name}");
|
||||
}
|
||||
|
||||
Drawable getAnimationWithFallback(string name, double frameLength)
|
||||
{
|
||||
Drawable animation = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(priorityLookup))
|
||||
{
|
||||
animation = skin.GetAnimation($"{priorityLookup}{name}", true, true, frameLength: frameLength);
|
||||
|
||||
if (!allowFallback)
|
||||
return animation;
|
||||
}
|
||||
|
||||
return animation ?? skin.GetAnimation($"hitcircle{name}", true, true, frameLength: frameLength);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
@ -12,7 +12,6 @@ using osu.Game.Tests.Beatmaps;
|
||||
namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(10000)]
|
||||
public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||
|
@ -95,7 +95,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.That(decodedAfterEncode, Is.Not.Null);
|
||||
|
||||
Assert.That(decodedAfterEncode.ScoreInfo.User.Username, Is.EqualTo(scoreInfo.User.Username));
|
||||
Assert.That(decodedAfterEncode.ScoreInfo.BeatmapInfoID, Is.EqualTo(scoreInfo.BeatmapInfoID));
|
||||
Assert.That(decodedAfterEncode.ScoreInfo.Ruleset, Is.EqualTo(scoreInfo.Ruleset));
|
||||
Assert.That(decodedAfterEncode.ScoreInfo.TotalScore, Is.EqualTo(scoreInfo.TotalScore));
|
||||
Assert.That(decodedAfterEncode.ScoreInfo.MaxCombo, Is.EqualTo(scoreInfo.MaxCombo));
|
||||
|
@ -93,7 +93,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
using (var stream = File.OpenRead(tempPath))
|
||||
{
|
||||
importedSet = await manager.Import(new ImportTask(stream, Path.GetFileName(tempPath)));
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
}
|
||||
|
||||
Assert.IsTrue(File.Exists(tempPath), "Stream source file somehow went missing");
|
||||
@ -171,7 +171,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var importedSecondTime = await osu.Dependencies.Get<BeatmapManager>().Import(new ImportTask(temp));
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
|
||||
// but contents doesn't, so existing should still be used.
|
||||
Assert.IsTrue(imported.ID == importedSecondTime.Value.ID);
|
||||
@ -225,7 +225,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var importedSecondTime = await osu.Dependencies.Get<BeatmapManager>().Import(new ImportTask(temp));
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
|
||||
// check the newly "imported" beatmap is not the original.
|
||||
Assert.IsTrue(imported.ID != importedSecondTime.Value.ID);
|
||||
@ -277,7 +277,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var importedSecondTime = await osu.Dependencies.Get<BeatmapManager>().Import(new ImportTask(temp));
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
|
||||
// check the newly "imported" beatmap is not the original.
|
||||
Assert.IsTrue(imported.ID != importedSecondTime.Value.ID);
|
||||
@ -328,7 +328,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var importedSecondTime = await osu.Dependencies.Get<BeatmapManager>().Import(new ImportTask(temp));
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
|
||||
// check the newly "imported" beatmap is not the original.
|
||||
Assert.IsTrue(imported.ID != importedSecondTime.Value.ID);
|
||||
@ -637,7 +637,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
if (!importer.ImportAsync(temp).Wait(10000))
|
||||
Assert.Fail(@"IPC took too long to send");
|
||||
|
||||
ensureLoaded(osu);
|
||||
ensureLoaded(osu).WaitSafely();
|
||||
|
||||
waitForOrAssert(() => !File.Exists(temp), "Temporary still exists after IPC import", 5000);
|
||||
}
|
||||
@ -659,7 +659,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
string temp = TestResources.GetTestBeatmapForImport();
|
||||
using (File.OpenRead(temp))
|
||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
File.Delete(temp);
|
||||
Assert.IsFalse(File.Exists(temp), "We likely held a read lock on the file when we shouldn't");
|
||||
}
|
||||
@ -698,7 +698,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -741,7 +741,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var imported = await osu.Dependencies.Get<BeatmapManager>().Import(new ImportTask(temp));
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
|
||||
Assert.IsFalse(imported.Value.Files.Any(f => f.Filename.Contains("subfolder")), "Files contain common subfolder");
|
||||
}
|
||||
@ -794,7 +794,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
|
||||
var imported = await osu.Dependencies.Get<BeatmapManager>().Import(new ImportTask(temp));
|
||||
|
||||
ensureLoaded(osu);
|
||||
await ensureLoaded(osu);
|
||||
|
||||
Assert.IsFalse(imported.Value.Files.Any(f => f.Filename.Contains("__MACOSX")), "Files contain resource fork folder, which should be ignored");
|
||||
Assert.IsFalse(imported.Value.Files.Any(f => f.Filename.Contains("actual_data")), "Files contain common subfolder");
|
||||
@ -812,7 +812,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestUpdateBeatmapInfo()
|
||||
public void TestUpdateBeatmapInfo()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||
{
|
||||
@ -822,7 +822,8 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
string temp = TestResources.GetTestBeatmapForImport();
|
||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
osu.Dependencies.Get<BeatmapManager>().Import(temp).WaitSafely();
|
||||
|
||||
// Update via the beatmap, not the beatmap info, to ensure correct linking
|
||||
BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
|
||||
@ -842,7 +843,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestUpdateBeatmapFile()
|
||||
public void TestUpdateBeatmapFile()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||
{
|
||||
@ -852,7 +853,8 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
string temp = TestResources.GetTestBeatmapForImport();
|
||||
await osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||
|
||||
osu.Dependencies.Get<BeatmapManager>().Import(temp).WaitSafely();
|
||||
|
||||
BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
|
||||
|
||||
@ -976,35 +978,35 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<BeatmapSetInfo> LoadQuickOszIntoOsu(OsuGameBase osu)
|
||||
public static Task<BeatmapSetInfo> LoadQuickOszIntoOsu(OsuGameBase osu) => Task.Factory.StartNew(() =>
|
||||
{
|
||||
string temp = TestResources.GetQuickTestBeatmapForImport();
|
||||
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
var importedSet = await manager.Import(new ImportTask(temp)).ConfigureAwait(false);
|
||||
var importedSet = manager.Import(new ImportTask(temp)).GetResultSafely();
|
||||
|
||||
ensureLoaded(osu);
|
||||
ensureLoaded(osu).WaitSafely();
|
||||
|
||||
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||
|
||||
return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.Value.ID);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
|
||||
public static async Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
|
||||
public static Task<BeatmapSetInfo> LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false) => Task.Factory.StartNew(() =>
|
||||
{
|
||||
string temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
|
||||
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
var importedSet = await manager.Import(new ImportTask(temp)).ConfigureAwait(false);
|
||||
var importedSet = manager.Import(new ImportTask(temp)).GetResultSafely();
|
||||
|
||||
ensureLoaded(osu);
|
||||
ensureLoaded(osu).WaitSafely();
|
||||
|
||||
waitForOrAssert(() => !File.Exists(temp), "Temporary file still exists after standard import", 5000);
|
||||
|
||||
return manager.GetAllUsableBeatmapSets().Find(beatmapSet => beatmapSet.ID == importedSet.Value.ID);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
|
||||
private void deleteBeatmapSet(BeatmapSetInfo imported, OsuGameBase osu)
|
||||
{
|
||||
@ -1053,7 +1055,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
Assert.AreEqual(expected, osu.Dependencies.Get<DatabaseContextFactory>().Get().FileInfo.Count(f => f.ReferenceCount == 1));
|
||||
}
|
||||
|
||||
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
||||
private static Task ensureLoaded(OsuGameBase osu, int timeout = 60000) => Task.Factory.StartNew(() =>
|
||||
{
|
||||
IEnumerable<BeatmapSetInfo> resultSets = null;
|
||||
var store = osu.Dependencies.Get<BeatmapManager>();
|
||||
@ -1089,14 +1091,14 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||
beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
||||
Assert.IsTrue(beatmap?.HitObjects.Any() == true);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
|
||||
private static void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 60000)
|
||||
{
|
||||
Task task = Task.Run(() =>
|
||||
Task task = Task.Factory.StartNew(() =>
|
||||
{
|
||||
while (!result()) Thread.Sleep(200);
|
||||
});
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
|
||||
Assert.IsTrue(task.Wait(timeout), failureMessage);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Tests.Beatmaps
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase osu)
|
||||
{
|
||||
importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).Result;
|
||||
importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).GetResultSafely();
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
|
@ -9,6 +9,21 @@ namespace osu.Game.Tests.Chat
|
||||
[TestFixture]
|
||||
public class MessageFormatterTests
|
||||
{
|
||||
private string originalWebsiteRootUrl;
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
originalWebsiteRootUrl = MessageFormatter.WebsiteRootUrl;
|
||||
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
MessageFormatter.WebsiteRootUrl = originalWebsiteRootUrl;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBareLink()
|
||||
{
|
||||
@ -32,8 +47,6 @@ namespace osu.Game.Tests.Chat
|
||||
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/discussions/123", "https://dev.ppy.sh/beatmapsets/discussions/123")]
|
||||
public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link)
|
||||
{
|
||||
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
|
||||
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = link });
|
||||
|
||||
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||
@ -47,7 +60,10 @@ namespace osu.Game.Tests.Chat
|
||||
[Test]
|
||||
public void TestMultipleComplexLinks()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a http://test.io/link#fragment. (see https://twitter.com). Also, This string should not be altered. http://example.com/" });
|
||||
Message result = MessageFormatter.FormatMessage(new Message
|
||||
{
|
||||
Content = "This is a http://test.io/link#fragment. (see https://twitter.com). Also, This string should not be altered. http://example.com/"
|
||||
});
|
||||
|
||||
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||
Assert.AreEqual(3, result.Links.Count);
|
||||
@ -104,7 +120,7 @@ namespace osu.Game.Tests.Chat
|
||||
|
||||
Assert.AreEqual("This is a Wiki Link.", result.DisplayContent);
|
||||
Assert.AreEqual(1, result.Links.Count);
|
||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(9, result.Links[0].Length);
|
||||
}
|
||||
@ -117,15 +133,15 @@ namespace osu.Game.Tests.Chat
|
||||
Assert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent);
|
||||
Assert.AreEqual(3, result.Links.Count);
|
||||
|
||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||
Assert.AreEqual(10, result.Links[0].Index);
|
||||
Assert.AreEqual(9, result.Links[0].Length);
|
||||
|
||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki:Link", result.Links[1].Url);
|
||||
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki:Link", result.Links[1].Url);
|
||||
Assert.AreEqual(20, result.Links[1].Index);
|
||||
Assert.AreEqual(9, result.Links[1].Length);
|
||||
|
||||
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki.Link", result.Links[2].Url);
|
||||
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki.Link", result.Links[2].Url);
|
||||
Assert.AreEqual(29, result.Links[2].Index);
|
||||
Assert.AreEqual(9, result.Links[2].Length);
|
||||
}
|
||||
@ -445,12 +461,15 @@ namespace osu.Game.Tests.Chat
|
||||
[Test]
|
||||
public void TestLinkComplex()
|
||||
{
|
||||
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [http://www.simple-test.com simple test] with some [traps] and [[wiki links]]. Don't forget to visit https://osu.ppy.sh (now!)[http://google.com]\uD83D\uDE12" });
|
||||
Message result = MessageFormatter.FormatMessage(new Message
|
||||
{
|
||||
Content = "This is a [http://www.simple-test.com simple test] with some [traps] and [[wiki links]]. Don't forget to visit https://osu.ppy.sh (now!)[http://google.com]\uD83D\uDE12"
|
||||
});
|
||||
|
||||
Assert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now!\0\0\0", result.DisplayContent);
|
||||
Assert.AreEqual(5, result.Links.Count);
|
||||
|
||||
Link f = result.Links.Find(l => l.Url == "https://osu.ppy.sh/wiki/wiki links");
|
||||
Link f = result.Links.Find(l => l.Url == "https://dev.ppy.sh/wiki/wiki links");
|
||||
Assert.That(f, Is.Not.Null);
|
||||
Assert.AreEqual(44, f.Index);
|
||||
Assert.AreEqual(10, f.Length);
|
||||
@ -514,8 +533,6 @@ namespace osu.Game.Tests.Chat
|
||||
[TestCase("https://dev.ppy.sh/home/changelog/lazer/2021.1012", "lazer/2021.1012")]
|
||||
public void TestChangelogLinks(string link, string expectedArg)
|
||||
{
|
||||
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
|
||||
|
||||
LinkDetails result = MessageFormatter.GetLinkDetails(link);
|
||||
|
||||
Assert.AreEqual(LinkAction.OpenChangelog, result.Action);
|
||||
|
@ -6,6 +6,7 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Tests.Resources;
|
||||
@ -179,7 +180,7 @@ namespace osu.Game.Tests.Collections.IO
|
||||
{
|
||||
// intentionally spin this up on a separate task to avoid disposal deadlocks.
|
||||
// see https://github.com/EventStore/EventStore/issues/1179
|
||||
await Task.Run(() => osu.CollectionManager.Import(stream).Wait());
|
||||
await Task.Factory.StartNew(() => osu.CollectionManager.Import(stream).WaitSafely(), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Models;
|
||||
@ -104,7 +105,7 @@ namespace osu.Game.Tests.Database
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realmFactory);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
|
||||
Debug.Assert(liveBeatmap != null);
|
||||
|
||||
@ -115,7 +116,7 @@ namespace osu.Game.Tests.Database
|
||||
Assert.IsTrue(beatmap.IsValid);
|
||||
Assert.IsFalse(beatmap.Hidden);
|
||||
});
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
});
|
||||
}
|
||||
|
||||
@ -133,7 +134,7 @@ namespace osu.Game.Tests.Database
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realmFactory);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
|
||||
Debug.Assert(liveBeatmap != null);
|
||||
|
||||
@ -141,7 +142,7 @@ namespace osu.Game.Tests.Database
|
||||
{
|
||||
liveBeatmap.PerformWrite(beatmap => { beatmap.Hidden = true; });
|
||||
liveBeatmap.PerformRead(beatmap => { Assert.IsTrue(beatmap.Hidden); });
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
});
|
||||
}
|
||||
|
||||
@ -175,7 +176,7 @@ namespace osu.Game.Tests.Database
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realmFactory);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
|
||||
Debug.Assert(liveBeatmap != null);
|
||||
|
||||
@ -195,7 +196,7 @@ namespace osu.Game.Tests.Database
|
||||
var __ = liveBeatmap.Value;
|
||||
});
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
});
|
||||
}
|
||||
|
||||
@ -213,7 +214,7 @@ namespace osu.Game.Tests.Database
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realmFactory);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
|
||||
Debug.Assert(liveBeatmap != null);
|
||||
|
||||
@ -223,7 +224,7 @@ namespace osu.Game.Tests.Database
|
||||
{
|
||||
var unused = liveBeatmap.Value;
|
||||
});
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
});
|
||||
}
|
||||
|
||||
@ -252,7 +253,7 @@ namespace osu.Game.Tests.Database
|
||||
|
||||
liveBeatmap = beatmap.ToLive(realmFactory);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).Wait();
|
||||
}, TaskCreationOptions.LongRunning | TaskCreationOptions.HideScheduler).WaitSafely();
|
||||
|
||||
Debug.Assert(liveBeatmap != null);
|
||||
|
||||
|
@ -6,6 +6,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Collections;
|
||||
using osu.Game.Tests.Resources;
|
||||
@ -58,7 +59,7 @@ namespace osu.Game.Tests
|
||||
{
|
||||
// Beatmap must be imported before the collection manager is loaded.
|
||||
if (withBeatmap)
|
||||
BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).Wait();
|
||||
BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely();
|
||||
|
||||
AddInternal(CollectionManager = new CollectionManager(Storage));
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
{
|
||||
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
||||
{
|
||||
Ruleset = new RulesetInfo { OnlineID = 5 },
|
||||
Ruleset = new RulesetInfo { OnlineID = 0 },
|
||||
RulesetID = 0,
|
||||
StarRating = 4.0d,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Utils;
|
||||
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
@ -42,9 +43,9 @@ namespace osu.Game.Tests.NonVisual
|
||||
|
||||
await Task.WhenAll(task1.task, task2.task, task3.task);
|
||||
|
||||
Assert.That(task1.task.Result, Is.EqualTo(1));
|
||||
Assert.That(task2.task.Result, Is.EqualTo(2));
|
||||
Assert.That(task3.task.Result, Is.EqualTo(3));
|
||||
Assert.That(task1.task.GetResultSafely(), Is.EqualTo(1));
|
||||
Assert.That(task2.task.GetResultSafely(), Is.EqualTo(2));
|
||||
Assert.That(task3.task.GetResultSafely(), Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -68,9 +69,9 @@ namespace osu.Game.Tests.NonVisual
|
||||
// Wait on both tasks.
|
||||
await Task.WhenAll(task1.task, task3.task);
|
||||
|
||||
Assert.That(task1.task.Result, Is.EqualTo(1));
|
||||
Assert.That(task1.task.GetResultSafely(), Is.EqualTo(1));
|
||||
Assert.That(task2.task.IsCompleted, Is.False);
|
||||
Assert.That(task3.task.Result, Is.EqualTo(2));
|
||||
Assert.That(task3.task.GetResultSafely(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -100,7 +100,7 @@ namespace osu.Game.Tests.Online
|
||||
public void TestTrackerRespectsSoftDeleting()
|
||||
{
|
||||
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
|
||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).Wait());
|
||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
|
||||
addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable);
|
||||
|
||||
AddStep("delete beatmap", () => beatmaps.Delete(beatmaps.QueryBeatmapSet(b => b.OnlineID == testBeatmapSet.OnlineID)));
|
||||
@ -114,12 +114,12 @@ namespace osu.Game.Tests.Online
|
||||
public void TestTrackerRespectsChecksum()
|
||||
{
|
||||
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
|
||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).Wait());
|
||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely());
|
||||
addAvailabilityCheckStep("initially locally available", BeatmapAvailability.LocallyAvailable);
|
||||
|
||||
AddStep("import altered beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetTestBeatmapForImport(true)).Wait();
|
||||
beatmaps.Import(TestResources.GetTestBeatmapForImport(true)).WaitSafely();
|
||||
});
|
||||
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
|
||||
|
||||
@ -129,7 +129,7 @@ namespace osu.Game.Tests.Online
|
||||
});
|
||||
addAvailabilityCheckStep("state not downloaded as well", BeatmapAvailability.NotDownloaded);
|
||||
|
||||
AddStep("reimport original beatmap", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait());
|
||||
AddStep("reimport original beatmap", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely());
|
||||
addAvailabilityCheckStep("locally available after re-import", BeatmapAvailability.LocallyAvailable);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO;
|
||||
@ -187,7 +188,7 @@ namespace osu.Game.Tests.Skins.IO
|
||||
|
||||
var imported = skinManager.Import(new ImportTask(exportStream, "exported.osk"));
|
||||
|
||||
imported.Result.PerformRead(s =>
|
||||
imported.GetResultSafely().PerformRead(s =>
|
||||
{
|
||||
Assert.IsFalse(s.Protected);
|
||||
Assert.AreNotEqual(originalSkinId, s.ID);
|
||||
@ -222,7 +223,7 @@ namespace osu.Game.Tests.Skins.IO
|
||||
|
||||
var imported = skinManager.Import(new ImportTask(exportStream, "exported.osk"));
|
||||
|
||||
imported.Result.PerformRead(s =>
|
||||
imported.GetResultSafely().PerformRead(s =>
|
||||
{
|
||||
Assert.IsFalse(s.Protected);
|
||||
Assert.AreNotEqual(originalSkinId, s.ID);
|
||||
|
@ -4,6 +4,7 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -24,7 +25,7 @@ namespace osu.Game.Tests.Skins
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).Result;
|
||||
var imported = beatmaps.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-beatmap.osz"))).GetResultSafely();
|
||||
beatmap = beatmaps.GetWorkingBeatmap(imported.Value.Beatmaps[0]);
|
||||
beatmap.LoadTrack();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.IO.Archives;
|
||||
@ -23,7 +24,7 @@ namespace osu.Game.Tests.Skins
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
var imported = skins.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-skin.osk"))).Result;
|
||||
var imported = skins.Import(new ZipArchiveReader(TestResources.OpenResource("Archives/ogg-skin.osk"))).GetResultSafely();
|
||||
skin = imported.PerformRead(skinInfo => skins.GetSkin(skinInfo));
|
||||
}
|
||||
|
||||
|
@ -6,18 +6,24 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Storyboards;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
@ -129,6 +135,46 @@ namespace osu.Game.Tests.Visual.Background
|
||||
AddAssert("top level background reused existing", () => screen.CheckLastLoadChange() == false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapBackgroundWithStoryboardClockAlwaysUsesCurrentTrack()
|
||||
{
|
||||
BackgroundScreenBeatmap nestedScreen = null;
|
||||
WorkingBeatmap originalWorking = null;
|
||||
|
||||
setSupporter(true);
|
||||
setSourceMode(BackgroundSource.BeatmapWithStoryboard);
|
||||
|
||||
AddStep("change beatmap", () => originalWorking = Beatmap.Value = createTestWorkingBeatmapWithStoryboard());
|
||||
AddAssert("background changed", () => screen.CheckLastLoadChange() == true);
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => getCurrentBackground()?.GetType() == typeof(BeatmapBackgroundWithStoryboard));
|
||||
|
||||
AddStep("start music", () => MusicController.Play());
|
||||
AddUntilStep("storyboard clock running", () => screen.ChildrenOfType<DrawableStoryboard>().SingleOrDefault()?.Clock.IsRunning == true);
|
||||
|
||||
// of note, this needs to be a type that doesn't match BackgroundScreenDefault else it is silently not pushed by the background stack.
|
||||
AddStep("push new background to stack", () => stack.Push(nestedScreen = new BackgroundScreenBeatmap(Beatmap.Value)));
|
||||
AddUntilStep("wait for screen to load", () => nestedScreen.IsLoaded && nestedScreen.IsCurrentScreen());
|
||||
|
||||
// we're testing a case where scheduling may be used to avoid issues, so ensure the scheduler is no longer running.
|
||||
AddUntilStep("wait for top level not alive", () => !screen.IsAlive);
|
||||
|
||||
AddStep("stop music", () => MusicController.Stop());
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithStoryboard());
|
||||
AddStep("change beatmap back", () => Beatmap.Value = originalWorking);
|
||||
AddStep("restart music", () => MusicController.Play());
|
||||
|
||||
AddAssert("top level background hasn't changed yet", () => screen.CheckLastLoadChange() == null);
|
||||
|
||||
AddStep("pop screen back to top level", () => screen.MakeCurrent());
|
||||
|
||||
AddStep("top level screen is current", () => screen.IsCurrentScreen());
|
||||
AddAssert("top level background reused existing", () => screen.CheckLastLoadChange() == false);
|
||||
AddUntilStep("storyboard clock running", () => screen.ChildrenOfType<DrawableStoryboard>().Single().Clock.IsRunning);
|
||||
|
||||
AddStep("stop music", () => MusicController.Stop());
|
||||
AddStep("restore default beatmap", () => Beatmap.SetDefault());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBackgroundTypeSwitch()
|
||||
{
|
||||
@ -198,6 +244,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
});
|
||||
|
||||
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(Audio);
|
||||
private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio);
|
||||
|
||||
private class TestBackgroundScreenDefault : BackgroundScreenDefault
|
||||
{
|
||||
@ -233,6 +280,51 @@ namespace osu.Game.Tests.Visual.Background
|
||||
protected override Texture GetBackground() => new Texture(1, 1);
|
||||
}
|
||||
|
||||
private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap
|
||||
{
|
||||
public TestWorkingBeatmapWithStoryboard(AudioManager audioManager)
|
||||
: base(new Beatmap(), createStoryboard(), audioManager)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Track GetBeatmapTrack() => new TrackVirtual(100000);
|
||||
|
||||
private static Storyboard createStoryboard()
|
||||
{
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Layers.Last().Add(new TestStoryboardElement());
|
||||
return storyboard;
|
||||
}
|
||||
|
||||
private class TestStoryboardElement : IStoryboardElementWithDuration
|
||||
{
|
||||
public string Path => string.Empty;
|
||||
public bool IsDrawable => true;
|
||||
public double StartTime => double.MinValue;
|
||||
public double EndTime => double.MaxValue;
|
||||
|
||||
public Drawable CreateDrawable() => new DrawableTestStoryboardElement();
|
||||
}
|
||||
|
||||
private class DrawableTestStoryboardElement : OsuSpriteText
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
public DrawableTestStoryboardElement()
|
||||
{
|
||||
Anchor = Origin = Anchor.Centre;
|
||||
Font = OsuFont.Default.With(size: 32);
|
||||
Text = "(not started)";
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
Text = Time.Current.ToString("N2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setCustomSkin()
|
||||
{
|
||||
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.
|
||||
|
@ -7,12 +7,14 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
@ -34,7 +36,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneUserDimBackgrounds : OsuManualInputManagerTestScene
|
||||
public class TestSceneUserDimBackgrounds : ScreenTestScene
|
||||
{
|
||||
private DummySongSelect songSelect;
|
||||
private TestPlayerLoader playerLoader;
|
||||
@ -49,19 +51,17 @@ namespace osu.Game.Tests.Visual.Background
|
||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
Dependencies.Cache(new OsuConfigManager(LocalStorage));
|
||||
|
||||
manager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
manager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
|
||||
Beatmap.SetDefault();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public virtual void SetUp() => Schedule(() =>
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
var stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
|
||||
Child = stack;
|
||||
base.SetUpSteps();
|
||||
|
||||
stack.Push(songSelect = new DummySongSelect());
|
||||
});
|
||||
AddStep("push song select", () => Stack.Push(songSelect = new DummySongSelect()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User settings should always be ignored on song select screen.
|
||||
@ -322,7 +322,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
public bool IsBackgroundUndimmed() => background.CurrentColour == Color4.White;
|
||||
|
||||
public bool IsUserBlurApplied() => background.CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
public bool IsUserBlurApplied() => Precision.AlmostEquals(background.CurrentBlur, new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR), 0.1f);
|
||||
|
||||
public bool IsUserBlurDisabled() => background.CurrentBlur == new Vector2(0);
|
||||
|
||||
@ -330,9 +330,9 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
public bool IsBackgroundVisible() => background.CurrentAlpha == 1;
|
||||
|
||||
public bool IsBackgroundBlur() => background.CurrentBlur == new Vector2(BACKGROUND_BLUR);
|
||||
public bool IsBackgroundBlur() => Precision.AlmostEquals(background.CurrentBlur, new Vector2(BACKGROUND_BLUR), 0.1f);
|
||||
|
||||
public bool CheckBackgroundBlur(Vector2 expected) => background.CurrentBlur == expected;
|
||||
public bool CheckBackgroundBlur(Vector2 expected) => Precision.AlmostEquals(background.CurrentBlur, expected, 0.1f);
|
||||
|
||||
/// <summary>
|
||||
/// Make sure every time a screen gets pushed, the background doesn't get replaced
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
@ -38,7 +39,7 @@ namespace osu.Game.Tests.Visual.Collections
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
|
||||
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
|
||||
base.Content.AddRange(new Drawable[]
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.Dialog;
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result);
|
||||
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely());
|
||||
base.SetUpSteps();
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -38,7 +39,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game).Result);
|
||||
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game).GetResultSafely());
|
||||
base.SetUpSteps();
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
@ -36,7 +37,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
protected override bool HasCustomSteps => true;
|
||||
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new NonImportingPlayer(false);
|
||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new FakeImportingPlayer(false);
|
||||
|
||||
protected new FakeImportingPlayer Player => (FakeImportingPlayer)base.Player;
|
||||
|
||||
protected override Ruleset CreatePlayerRuleset() => createCustomRuleset?.Invoke() ?? new OsuRuleset();
|
||||
|
||||
@ -54,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestNoSubmissionOnResultsWithNoToken()
|
||||
{
|
||||
prepareTokenResponse(false);
|
||||
prepareTestAPI(false);
|
||||
|
||||
createPlayerTest();
|
||||
|
||||
@ -74,7 +77,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestSubmissionOnResults()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest();
|
||||
|
||||
@ -93,7 +96,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestSubmissionForDifferentRuleset()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(createRuleset: () => new TaikoRuleset());
|
||||
|
||||
@ -113,7 +116,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestSubmissionForConvertedBeatmap()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(createRuleset: () => new ManiaRuleset(), createBeatmap: _ => createTestBeatmap(new OsuRuleset().RulesetInfo));
|
||||
|
||||
@ -133,7 +136,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestNoSubmissionOnExitWithNoToken()
|
||||
{
|
||||
prepareTokenResponse(false);
|
||||
prepareTestAPI(false);
|
||||
|
||||
createPlayerTest();
|
||||
|
||||
@ -150,7 +153,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestNoSubmissionOnEmptyFail()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(true);
|
||||
|
||||
@ -165,7 +168,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestSubmissionOnFail()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(true);
|
||||
|
||||
@ -182,7 +185,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestNoSubmissionOnEmptyExit()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest();
|
||||
|
||||
@ -195,7 +198,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestSubmissionOnExit()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest();
|
||||
|
||||
@ -207,10 +210,29 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("ensure failing submission", () => Player.SubmittedScore?.ScoreInfo.Passed == false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSubmissionOnExitDuringImport()
|
||||
{
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest();
|
||||
AddStep("block imports", () => Player.AllowImportCompletion.Wait());
|
||||
|
||||
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
|
||||
|
||||
addFakeHit();
|
||||
|
||||
AddUntilStep("wait for import to start", () => Player.ScoreImportStarted);
|
||||
|
||||
AddStep("exit", () => Player.Exit());
|
||||
AddStep("allow import to proceed", () => Player.AllowImportCompletion.Release(1));
|
||||
AddUntilStep("ensure submission", () => Player.SubmittedScore != null && Player.ImportedScore != null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoSubmissionOnLocalBeatmap()
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(false, r =>
|
||||
{
|
||||
@ -231,7 +253,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[TestCase(10)]
|
||||
public void TestNoSubmissionOnCustomRuleset(int? rulesetId)
|
||||
{
|
||||
prepareTokenResponse(true);
|
||||
prepareTestAPI(true);
|
||||
|
||||
createPlayerTest(false, createRuleset: () => new OsuRuleset { RulesetInfo = { OnlineID = rulesetId ?? -1 } });
|
||||
|
||||
@ -253,7 +275,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
}));
|
||||
}
|
||||
|
||||
private void prepareTokenResponse(bool validToken)
|
||||
private void prepareTestAPI(bool validToken)
|
||||
{
|
||||
AddStep("Prepare test API", () =>
|
||||
{
|
||||
@ -267,6 +289,31 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
else
|
||||
tokenRequest.TriggerFailure(new APIException("something went wrong!", null));
|
||||
return true;
|
||||
|
||||
case SubmitSoloScoreRequest submissionRequest:
|
||||
if (validToken)
|
||||
{
|
||||
var requestScore = submissionRequest.Score;
|
||||
|
||||
submissionRequest.TriggerSuccess(new MultiplayerScore
|
||||
{
|
||||
ID = 1234,
|
||||
User = dummyAPI.LocalUser.Value,
|
||||
Rank = requestScore.Rank,
|
||||
TotalScore = requestScore.TotalScore,
|
||||
Accuracy = requestScore.Accuracy,
|
||||
MaxCombo = requestScore.MaxCombo,
|
||||
Mods = requestScore.Mods,
|
||||
Statistics = requestScore.Statistics,
|
||||
Passed = requestScore.Passed,
|
||||
EndedAt = DateTimeOffset.Now,
|
||||
Position = 1
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -288,15 +335,26 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
}
|
||||
|
||||
private class NonImportingPlayer : TestPlayer
|
||||
protected class FakeImportingPlayer : TestPlayer
|
||||
{
|
||||
public NonImportingPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
|
||||
public bool ScoreImportStarted { get; set; }
|
||||
public SemaphoreSlim AllowImportCompletion { get; }
|
||||
public Score ImportedScore { get; private set; }
|
||||
|
||||
public FakeImportingPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
|
||||
: base(allowPause, showResults, pauseOnFocusLost)
|
||||
{
|
||||
AllowImportCompletion = new SemaphoreSlim(1);
|
||||
}
|
||||
|
||||
protected override Task ImportScore(Score score)
|
||||
protected override async Task ImportScore(Score score)
|
||||
{
|
||||
ScoreImportStarted = true;
|
||||
|
||||
await AllowImportCompletion.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
ImportedScore = score;
|
||||
|
||||
// It was discovered that Score members could sometimes be half-populated.
|
||||
// In particular, the RulesetID property could be set to 0 even on non-osu! maps.
|
||||
// We want to test that the state of that property is consistent in this test.
|
||||
@ -311,8 +369,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
// In the above instance, if a ScoreInfo with Ruleset = {mania} and RulesetID = 0 is attached to an EF context,
|
||||
// RulesetID WILL BE SILENTLY SET TO THE CORRECT VALUE of 3.
|
||||
//
|
||||
// For the above reasons, importing is disabled in this test.
|
||||
return Task.CompletedTask;
|
||||
// For the above reasons, actual importing is disabled in this test.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -135,7 +136,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded);
|
||||
|
||||
AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)).Result);
|
||||
AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true)).GetResultSafely());
|
||||
|
||||
AddUntilStep("state is available", () => downloadButton.State.Value == DownloadState.LocallyAvailable);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -60,7 +61,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
|
||||
importedBeatmap = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
|
||||
importedBeatmapId = importedBeatmap.Beatmaps.First(b => b.RulesetID == 0).OnlineID ?? -1;
|
||||
});
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
CreateTest(null);
|
||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||
AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space));
|
||||
AddAssert("player is no longer current screen", () => !Player.IsCurrentScreen());
|
||||
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
||||
AddUntilStep("time less than storyboard duration", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < currentStoryboardDuration);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
@ -33,11 +34,11 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
Queue<(IWorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
|
||||
|
||||
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
|
||||
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()).Wait(), 5);
|
||||
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()).WaitSafely(), 5);
|
||||
|
||||
AddStep("import beatmap with track", () =>
|
||||
{
|
||||
var setWithTrack = Game.BeatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).Result;
|
||||
var setWithTrack = Game.BeatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).GetResultSafely();
|
||||
Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(setWithTrack.Value.Beatmaps.First());
|
||||
});
|
||||
|
||||
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -56,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
InitialBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
||||
OtherBeatmap = importedSet.Beatmaps.Last(b => b.RulesetID == 0);
|
||||
|
@ -1,13 +1,25 @@
|
||||
// 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 enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
@ -83,16 +95,60 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
|
||||
}
|
||||
|
||||
private void addItem(Func<BeatmapInfo> beatmap)
|
||||
[Test]
|
||||
public void TestCorrectRulesetSelectedAfterNewItemAdded()
|
||||
{
|
||||
addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo);
|
||||
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
|
||||
|
||||
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
|
||||
ClickButtonWhenEnabled<MultiplayerReadyButton>();
|
||||
|
||||
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
|
||||
ClickButtonWhenEnabled<MultiplayerReadyButton>();
|
||||
|
||||
AddUntilStep("wait for player", () => CurrentScreen is Player player && player.IsLoaded);
|
||||
AddAssert("ruleset is correct", () => ((Player)CurrentScreen).Ruleset.Value.Equals(new OsuRuleset().RulesetInfo));
|
||||
AddStep("exit player", () => CurrentScreen.Exit());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCorrectModsSelectedAfterNewItemAdded()
|
||||
{
|
||||
addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() });
|
||||
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
|
||||
|
||||
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
|
||||
ClickButtonWhenEnabled<MultiplayerReadyButton>();
|
||||
|
||||
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
|
||||
ClickButtonWhenEnabled<MultiplayerReadyButton>();
|
||||
|
||||
AddUntilStep("wait for player", () => CurrentScreen is Player player && player.IsLoaded);
|
||||
AddAssert("mods are correct", () => !((Player)CurrentScreen).Mods.Value.Any());
|
||||
AddStep("exit player", () => CurrentScreen.Exit());
|
||||
}
|
||||
|
||||
private void addItem(Func<BeatmapInfo> beatmap, RulesetInfo? ruleset = null, IReadOnlyList<Mod>? mods = null)
|
||||
{
|
||||
Screens.Select.SongSelect? songSelect = null;
|
||||
|
||||
AddStep("click add button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerMatchSubScreen.AddItemButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded);
|
||||
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(beatmap()));
|
||||
AddUntilStep("wait for song select", () => (songSelect = CurrentSubScreen as Screens.Select.SongSelect) != null);
|
||||
AddUntilStep("wait for loaded", () => songSelect.AsNonNull().BeatmapSetsLoaded);
|
||||
|
||||
if (ruleset != null)
|
||||
AddStep($"set {ruleset.Name} ruleset", () => songSelect.AsNonNull().Ruleset.Value = ruleset);
|
||||
|
||||
if (mods != null)
|
||||
AddStep($"set mods to {string.Join(",", mods.Select(m => m.Acronym))}", () => songSelect.AsNonNull().Mods.Value = mods);
|
||||
|
||||
AddStep("select other beatmap", () => songSelect.AsNonNull().FinaliseSelection(beatmap()));
|
||||
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
@ -153,7 +154,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
||||
|
||||
AddStep("import beatmap", () => manager.Import(beatmap.BeatmapSet).Wait());
|
||||
AddStep("import beatmap", () => manager.Import(beatmap.BeatmapSet).WaitSafely());
|
||||
|
||||
createPlaylistWithBeatmaps(beatmap);
|
||||
|
||||
|
@ -50,6 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
|
||||
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
||||
AddUntilStep("wait for user population", () => leaderboard.ChildrenOfType<GameplayLeaderboardScore>().Count() == 2);
|
||||
|
||||
AddStep("add clock sources", () =>
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -46,7 +47,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
importedSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result;
|
||||
importedSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely();
|
||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
||||
importedBeatmapId = importedBeatmap.OnlineID ?? -1;
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
@ -22,6 +24,8 @@ using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.OnlinePlay.Components;
|
||||
@ -67,7 +71,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
});
|
||||
|
||||
@ -438,6 +442,84 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddAssert("Beatmap matches current item", () => Beatmap.Value.BeatmapInfo.OnlineID == client.Room?.Playlist.First().BeatmapID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect()
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pressReadyButton();
|
||||
|
||||
AddStep("Enter song select", () =>
|
||||
{
|
||||
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
||||
|
||||
AddAssert("Ruleset matches current item", () => Ruleset.Value.OnlineID == client.Room?.Playlist.First().RulesetID);
|
||||
|
||||
AddStep("Switch ruleset", () => ((MultiplayerMatchSongSelect)multiplayerComponents.MultiplayerScreen.CurrentSubScreen).Ruleset.Value = new CatchRuleset().RulesetInfo);
|
||||
|
||||
AddUntilStep("Ruleset doesn't match current item", () => Ruleset.Value.OnlineID != client.Room?.Playlist.First().RulesetID);
|
||||
|
||||
AddStep("start match externally", () => client.StartMatch());
|
||||
|
||||
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is Player);
|
||||
|
||||
AddAssert("Ruleset matches current item", () => Ruleset.Value.OnlineID == client.Room?.Playlist.First().RulesetID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlayStartsWithCorrectModsWhileAtSongSelect()
|
||||
{
|
||||
createRoom(() => new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pressReadyButton();
|
||||
|
||||
AddStep("Enter song select", () =>
|
||||
{
|
||||
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerComponents.CurrentScreen).CurrentSubScreen;
|
||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
||||
|
||||
AddAssert("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(client.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
|
||||
|
||||
AddStep("Switch required mods", () => ((MultiplayerMatchSongSelect)multiplayerComponents.MultiplayerScreen.CurrentSubScreen).Mods.Value = new Mod[] { new OsuModDoubleTime() });
|
||||
|
||||
AddAssert("Mods don't match current item", () => !SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(client.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
|
||||
|
||||
AddStep("start match externally", () => client.StartMatch());
|
||||
|
||||
AddUntilStep("play started", () => multiplayerComponents.CurrentScreen is Player);
|
||||
|
||||
AddAssert("Mods match current item", () => SelectedMods.Value.Select(m => m.Acronym).SequenceEqual(client.Room.AsNonNull().Playlist.First().RequiredMods.Select(m => m.Acronym)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLocalPlayDoesNotStartWhileSpectatingWithNoBeatmap()
|
||||
{
|
||||
@ -505,7 +587,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("restore beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
});
|
||||
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Utils;
|
||||
@ -43,7 +44,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).Result);
|
||||
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).GetResultSafely());
|
||||
|
||||
AddStep("create leaderboard", () =>
|
||||
{
|
||||
@ -90,7 +91,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
public void TestUserQuit()
|
||||
{
|
||||
foreach (int user in users)
|
||||
AddStep($"mark user {user} quit", () => Client.RemoveUser(LookupCache.GetUserAsync(user).Result.AsNonNull()));
|
||||
AddStep($"mark user {user} quit", () => Client.RemoveUser(LookupCache.GetUserAsync(user).GetResultSafely().AsNonNull()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Online.API;
|
||||
@ -47,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).Result);
|
||||
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).GetResultSafely());
|
||||
|
||||
AddStep("create leaderboard", () =>
|
||||
{
|
||||
|
@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
beatmapSetInfo.Beatmaps.Add(beatmap);
|
||||
}
|
||||
|
||||
manager.Import(beatmapSetInfo).Wait();
|
||||
manager.Import(beatmapSetInfo).WaitSafely();
|
||||
}
|
||||
|
||||
public override void SetUpSteps()
|
||||
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -39,7 +40,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
||||
});
|
||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
@ -58,7 +59,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
importedBeatmap = importedSet.Beatmaps.First(b => b.RulesetID == 0);
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
@ -41,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
|
@ -8,6 +8,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Utils;
|
||||
@ -38,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
var beatmapSet = TestResources.CreateTestBeatmapSetInfo();
|
||||
|
||||
manager.Import(beatmapSet).Wait();
|
||||
manager.Import(beatmapSet).WaitSafely();
|
||||
}
|
||||
|
||||
public override void SetUpSteps()
|
||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -51,7 +52,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("import beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First();
|
||||
});
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
@ -82,7 +83,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
PushAndConfirm(() => songSelect = new TestSceneScreenNavigation.TestPlaySongSelect());
|
||||
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait());
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).WaitSafely());
|
||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -172,7 +173,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
private void importAndWaitForSongSelect()
|
||||
{
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||
PushAndConfirm(() => new TestPlaySongSelect());
|
||||
AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID == 241526);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
@ -126,7 +127,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
||||
},
|
||||
}
|
||||
}).Result.Value;
|
||||
}).GetResultSafely().Value;
|
||||
});
|
||||
|
||||
AddAssert($"import {i} succeeded", () => imported != null);
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -57,7 +58,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
Ruleset = new OsuRuleset().RulesetInfo
|
||||
},
|
||||
}
|
||||
}).Result.Value;
|
||||
}).GetResultSafely().Value;
|
||||
});
|
||||
}
|
||||
|
||||
@ -131,7 +132,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
OnlineID = i,
|
||||
BeatmapInfo = beatmap.Beatmaps.First(),
|
||||
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
||||
}).Result.Value;
|
||||
}).GetResultSafely().Value;
|
||||
});
|
||||
|
||||
AddAssert($"import {i} succeeded", () => imported != null);
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -70,7 +71,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||
|
||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||
|
||||
@ -104,7 +105,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||
|
||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||
|
||||
@ -138,7 +139,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait());
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).WaitSafely());
|
||||
|
||||
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
|
||||
|
||||
|
@ -107,19 +107,31 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCorrectOldContentExpiration()
|
||||
{
|
||||
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||
|
||||
AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray()));
|
||||
assertAllCardsOfType<BeatmapCardNormal>(100);
|
||||
|
||||
AddStep("show more results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 30).ToArray()));
|
||||
assertAllCardsOfType<BeatmapCardNormal>(30);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCardSizeSwitching()
|
||||
{
|
||||
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
|
||||
|
||||
AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray()));
|
||||
assertAllCardsOfType<BeatmapCardNormal>();
|
||||
assertAllCardsOfType<BeatmapCardNormal>(100);
|
||||
|
||||
setCardSize(BeatmapCardSize.Extra);
|
||||
assertAllCardsOfType<BeatmapCardExtra>();
|
||||
assertAllCardsOfType<BeatmapCardExtra>(100);
|
||||
|
||||
setCardSize(BeatmapCardSize.Normal);
|
||||
assertAllCardsOfType<BeatmapCardNormal>();
|
||||
assertAllCardsOfType<BeatmapCardNormal>(100);
|
||||
|
||||
AddStep("fetch for 0 beatmaps", () => fetchFor());
|
||||
AddUntilStep("placeholder shown", () => overlay.ChildrenOfType<BeatmapListingOverlay.NotFoundDrawable>().SingleOrDefault()?.IsPresent == true);
|
||||
@ -323,13 +335,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private void setCardSize(BeatmapCardSize cardSize) => AddStep($"set card size to {cardSize}", () => overlay.ChildrenOfType<BeatmapListingCardSizeTabControl>().Single().Current.Value = cardSize);
|
||||
|
||||
private void assertAllCardsOfType<T>()
|
||||
private void assertAllCardsOfType<T>(int expectedCount)
|
||||
where T : BeatmapCard =>
|
||||
AddUntilStep($"all loaded beatmap cards are {typeof(T)}", () =>
|
||||
{
|
||||
int loadedCorrectCount = this.ChildrenOfType<BeatmapCard>().Count(card => card.IsLoaded && card.GetType() == typeof(T));
|
||||
int totalCount = this.ChildrenOfType<BeatmapCard>().Count();
|
||||
return loadedCorrectCount > 0 && loadedCorrectCount == totalCount;
|
||||
return loadedCorrectCount > 0 && loadedCorrectCount == expectedCount;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -50,63 +50,24 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
Dependencies.Cache(new ChatOverlay());
|
||||
Dependencies.Cache(dialogOverlay);
|
||||
|
||||
testLinksGeneral();
|
||||
testEcho();
|
||||
}
|
||||
|
||||
private void clear() => AddStep("clear messages", textContainer.Clear);
|
||||
|
||||
private void addMessageWithChecks(string text, int linkAmount = 0, bool isAction = false, bool isImportant = false, params LinkAction[] expectedActions)
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
int index = textContainer.Count + 1;
|
||||
var newLine = new ChatLine(new DummyMessage(text, isAction, isImportant, index));
|
||||
textContainer.Add(newLine);
|
||||
textContainer.Clear();
|
||||
});
|
||||
|
||||
AddAssert($"msg #{index} has {linkAmount} link(s)", () => newLine.Message.Links.Count == linkAmount);
|
||||
AddAssert($"msg #{index} has the right action", hasExpectedActions);
|
||||
//AddAssert($"msg #{index} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic());
|
||||
AddAssert($"msg #{index} shows {linkAmount} link(s)", isShowingLinks);
|
||||
|
||||
bool hasExpectedActions()
|
||||
{
|
||||
var expectedActionsList = expectedActions.ToList();
|
||||
|
||||
if (expectedActionsList.Count != newLine.Message.Links.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < newLine.Message.Links.Count; i++)
|
||||
{
|
||||
var action = newLine.Message.Links[i].Action;
|
||||
if (action != expectedActions[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast<OsuSpriteText>().All(sprite => sprite.Font.Italics);
|
||||
|
||||
bool isShowingLinks()
|
||||
{
|
||||
bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
|
||||
|
||||
Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
|
||||
|
||||
var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
|
||||
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
|
||||
|
||||
return linkSprites.All(d => d.Colour == linkColour)
|
||||
&& newLine.ContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour);
|
||||
}
|
||||
}
|
||||
|
||||
private void testLinksGeneral()
|
||||
[Test]
|
||||
public void TestLinksGeneral()
|
||||
{
|
||||
int messageIndex = 0;
|
||||
|
||||
addMessageWithChecks("test!");
|
||||
addMessageWithChecks("dev.ppy.sh!");
|
||||
addMessageWithChecks("https://dev.ppy.sh!", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("00:12:345 (1,2) - Test?", 1, expectedActions: LinkAction.OpenEditorTimestamp);
|
||||
addMessageWithChecks("Wiki link for tasty [[Performance Points]]", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("Wiki link for tasty [[Performance Points]]", 1, expectedActions: LinkAction.OpenWiki);
|
||||
addMessageWithChecks("(osu forums)[https://dev.ppy.sh/forum] (old link format)", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("[https://dev.ppy.sh/home New site] (new link format)", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("[osu forums](https://dev.ppy.sh/forum) (new link format 2)", 1, expectedActions: LinkAction.External);
|
||||
@ -117,7 +78,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
expectedActions: new[] { LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External });
|
||||
addMessageWithChecks("[https://dev.ppy.sh/home New link format with escaped [and \\[ paired] braces]", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("[Markdown link format with escaped [and \\[ paired] braces](https://dev.ppy.sh/home)", 1, expectedActions: LinkAction.External);
|
||||
addMessageWithChecks("(Old link format with escaped (and \\( paired) parentheses)[https://dev.ppy.sh/home] and [[also a rogue wiki link]]", 2, expectedActions: new[] { LinkAction.External, LinkAction.External });
|
||||
addMessageWithChecks("(Old link format with escaped (and \\( paired) parentheses)[https://dev.ppy.sh/home] and [[also a rogue wiki link]]", 2,
|
||||
expectedActions: new[] { LinkAction.External, LinkAction.OpenWiki });
|
||||
// note that there's 0 links here (they get removed if a channel is not found)
|
||||
addMessageWithChecks("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).");
|
||||
addMessageWithChecks("I am important!", 0, false, true);
|
||||
@ -129,11 +91,60 @@ namespace osu.Game.Tests.Visual.Online
|
||||
addMessageWithChecks("Join my osu://chan/#english.", 1, expectedActions: LinkAction.OpenChannel);
|
||||
addMessageWithChecks("Join my #english or #japanese channels.", 2, expectedActions: new[] { LinkAction.OpenChannel, LinkAction.OpenChannel });
|
||||
addMessageWithChecks("Join my #english or #nonexistent #hashtag channels.", 1, expectedActions: LinkAction.OpenChannel);
|
||||
|
||||
void addMessageWithChecks(string text, int linkAmount = 0, bool isAction = false, bool isImportant = false, params LinkAction[] expectedActions)
|
||||
{
|
||||
ChatLine newLine = null;
|
||||
int index = messageIndex++;
|
||||
|
||||
AddStep("add message", () =>
|
||||
{
|
||||
newLine = new ChatLine(new DummyMessage(text, isAction, isImportant, index));
|
||||
textContainer.Add(newLine);
|
||||
});
|
||||
|
||||
AddAssert($"msg #{index} has {linkAmount} link(s)", () => newLine.Message.Links.Count == linkAmount);
|
||||
AddAssert($"msg #{index} has the right action", hasExpectedActions);
|
||||
//AddAssert($"msg #{index} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic());
|
||||
AddAssert($"msg #{index} shows {linkAmount} link(s)", isShowingLinks);
|
||||
|
||||
bool hasExpectedActions()
|
||||
{
|
||||
var expectedActionsList = expectedActions.ToList();
|
||||
|
||||
if (expectedActionsList.Count != newLine.Message.Links.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < newLine.Message.Links.Count; i++)
|
||||
{
|
||||
var action = newLine.Message.Links[i].Action;
|
||||
if (action != expectedActions[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast<OsuSpriteText>().All(sprite => sprite.Font.Italics);
|
||||
|
||||
bool isShowingLinks()
|
||||
{
|
||||
bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
|
||||
|
||||
Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
|
||||
|
||||
var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
|
||||
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
|
||||
|
||||
return linkSprites.All(d => d.Colour == linkColour)
|
||||
&& newLine.ContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testEcho()
|
||||
[Test]
|
||||
public void TestEcho()
|
||||
{
|
||||
int echoCounter = 0;
|
||||
int messageIndex = 0;
|
||||
|
||||
addEchoWithWait("sent!", "received!");
|
||||
addEchoWithWait("https://dev.ppy.sh/home", null, 500);
|
||||
@ -142,15 +153,16 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
void addEchoWithWait(string text, string completeText = null, double delay = 250)
|
||||
{
|
||||
var newLine = new ChatLine(new DummyEchoMessage(text));
|
||||
int index = messageIndex++;
|
||||
|
||||
AddStep($"send msg #{++echoCounter} after {delay}ms", () =>
|
||||
AddStep($"send msg #{index} after {delay}ms", () =>
|
||||
{
|
||||
ChatLine newLine = new ChatLine(new DummyEchoMessage(text));
|
||||
textContainer.Add(newLine);
|
||||
Scheduler.AddDelayed(() => newLine.Message = new DummyMessage(completeText ?? text), delay);
|
||||
});
|
||||
|
||||
AddUntilStep($"wait for msg #{echoCounter}", () => textContainer.All(line => line.Message is DummyMessage));
|
||||
AddUntilStep($"wait for msg #{index}", () => textContainer.All(line => line.Message is DummyMessage));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,27 @@
|
||||
// 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 osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Overlays.Rankings.Tables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Rulesets;
|
||||
using System.Threading;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Rankings;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneRankingsTables : OsuTestScene
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
private readonly BasicScrollContainer scrollFlow;
|
||||
private readonly LoadingLayer loading;
|
||||
private CancellationTokenSource cancellationToken;
|
||||
private APIRequest request;
|
||||
|
||||
public TestSceneRankingsTables()
|
||||
{
|
||||
@ -53,73 +42,120 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
AddStep("Osu performance", () => createPerformanceTable(new OsuRuleset().RulesetInfo, null));
|
||||
AddStep("Mania scores", () => createScoreTable(new ManiaRuleset().RulesetInfo));
|
||||
AddStep("Taiko country scores", () => createCountryTable(new TaikoRuleset().RulesetInfo));
|
||||
AddStep("Catch US performance page 10", () => createPerformanceTable(new CatchRuleset().RulesetInfo, "US", 10));
|
||||
AddStep("Osu spotlight table (chart 271)", () => createSpotlightTable(new OsuRuleset().RulesetInfo, 271));
|
||||
AddStep("User performance", createPerformanceTable);
|
||||
AddStep("User scores", createScoreTable);
|
||||
AddStep("Country scores", createCountryTable);
|
||||
}
|
||||
|
||||
private void createCountryTable(RulesetInfo ruleset, int page = 1)
|
||||
private void createCountryTable()
|
||||
{
|
||||
onLoadStarted();
|
||||
|
||||
request = new GetCountryRankingsRequest(ruleset, page);
|
||||
((GetCountryRankingsRequest)request).Success += rankings => Schedule(() =>
|
||||
var countries = new List<CountryStatistics>
|
||||
{
|
||||
var table = new CountriesTable(page, rankings.Countries);
|
||||
loadTable(table);
|
||||
});
|
||||
new CountryStatistics
|
||||
{
|
||||
Country = new Country { FlagName = "US", FullName = "United States" },
|
||||
FlagName = "US",
|
||||
ActiveUsers = 2_972_623,
|
||||
PlayCount = 3_086_515_743,
|
||||
RankedScore = 449_407_643_332_546,
|
||||
Performance = 371_974_024
|
||||
},
|
||||
new CountryStatistics
|
||||
{
|
||||
Country = new Country { FlagName = "RU", FullName = "Russian Federation" },
|
||||
FlagName = "RU",
|
||||
ActiveUsers = 1_609_989,
|
||||
PlayCount = 1_637_052_841,
|
||||
RankedScore = 221_660_827_473_004,
|
||||
Performance = 163_426_476
|
||||
}
|
||||
};
|
||||
|
||||
api.Queue(request);
|
||||
var table = new CountriesTable(1, countries);
|
||||
loadTable(table);
|
||||
}
|
||||
|
||||
private void createPerformanceTable(RulesetInfo ruleset, string country, int page = 1)
|
||||
private static List<UserStatistics> createUserStatistics() => new List<UserStatistics>
|
||||
{
|
||||
new UserStatistics
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = "first active user",
|
||||
Country = new Country { FlagName = "JP" },
|
||||
Active = true,
|
||||
},
|
||||
Accuracy = 0.9972,
|
||||
PlayCount = 233_215,
|
||||
TotalScore = 983_231_234_656,
|
||||
RankedScore = 593_231_345_897,
|
||||
PP = 23_934,
|
||||
GradesCount = new UserStatistics.Grades
|
||||
{
|
||||
SS = 35_132,
|
||||
S = 23_345,
|
||||
A = 12_234
|
||||
}
|
||||
},
|
||||
new UserStatistics
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = "inactive user",
|
||||
Country = new Country { FlagName = "AU" },
|
||||
Active = false,
|
||||
},
|
||||
Accuracy = 0.9831,
|
||||
PlayCount = 195_342,
|
||||
TotalScore = 683_231_234_656,
|
||||
RankedScore = 393_231_345_897,
|
||||
PP = 20_934,
|
||||
GradesCount = new UserStatistics.Grades
|
||||
{
|
||||
SS = 32_132,
|
||||
S = 20_345,
|
||||
A = 9_234
|
||||
}
|
||||
},
|
||||
new UserStatistics
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Username = "second active user",
|
||||
Country = new Country { FlagName = "PL" },
|
||||
Active = true,
|
||||
},
|
||||
Accuracy = 0.9584,
|
||||
PlayCount = 100_903,
|
||||
TotalScore = 97_242_983_434,
|
||||
RankedScore = 3_156_345_897,
|
||||
PP = 9_568,
|
||||
GradesCount = new UserStatistics.Grades
|
||||
{
|
||||
SS = 13_152,
|
||||
S = 24_375,
|
||||
A = 9_960
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
private void createPerformanceTable()
|
||||
{
|
||||
onLoadStarted();
|
||||
|
||||
request = new GetUserRankingsRequest(ruleset, country: country, page: page);
|
||||
((GetUserRankingsRequest)request).Success += rankings => Schedule(() =>
|
||||
{
|
||||
var table = new PerformanceTable(page, rankings.Users);
|
||||
loadTable(table);
|
||||
});
|
||||
|
||||
api.Queue(request);
|
||||
loadTable(new PerformanceTable(1, createUserStatistics()));
|
||||
}
|
||||
|
||||
private void createScoreTable(RulesetInfo ruleset, int page = 1)
|
||||
private void createScoreTable()
|
||||
{
|
||||
onLoadStarted();
|
||||
|
||||
request = new GetUserRankingsRequest(ruleset, UserRankingsType.Score, page);
|
||||
((GetUserRankingsRequest)request).Success += rankings => Schedule(() =>
|
||||
{
|
||||
var table = new ScoresTable(page, rankings.Users);
|
||||
loadTable(table);
|
||||
});
|
||||
|
||||
api.Queue(request);
|
||||
}
|
||||
|
||||
private void createSpotlightTable(RulesetInfo ruleset, int spotlight)
|
||||
{
|
||||
onLoadStarted();
|
||||
|
||||
request = new GetSpotlightRankingsRequest(ruleset, spotlight, RankingsSortCriteria.All);
|
||||
((GetSpotlightRankingsRequest)request).Success += rankings => Schedule(() =>
|
||||
{
|
||||
var table = new ScoresTable(1, rankings.Users);
|
||||
loadTable(table);
|
||||
});
|
||||
|
||||
api.Queue(request);
|
||||
loadTable(new ScoresTable(1, createUserStatistics()));
|
||||
}
|
||||
|
||||
private void onLoadStarted()
|
||||
{
|
||||
loading.Show();
|
||||
request?.Cancel();
|
||||
cancellationToken?.Cancel();
|
||||
cancellationToken = new CancellationTokenSource();
|
||||
}
|
||||
|
57
osu.Game.Tests/Visual/Online/TestSceneScoreboardTime.cs
Normal file
57
osu.Game.Tests/Visual/Online/TestSceneScoreboardTime.cs
Normal file
@ -0,0 +1,57 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneScoreboardTime : OsuTestScene
|
||||
{
|
||||
private StopwatchClock stopwatch;
|
||||
|
||||
[Test]
|
||||
public void TestVariousUnits()
|
||||
{
|
||||
AddStep("create various scoreboard times", () => Child = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Clock = new FramedClock(stopwatch = new StopwatchClock()), // prevent time from naturally elapsing.
|
||||
Direction = FillDirection.Vertical,
|
||||
ChildrenEnumerable = testCases.Select(dateTime => new ScoreboardTime(dateTime, 24).With(time => time.Anchor = time.Origin = Anchor.TopCentre))
|
||||
});
|
||||
|
||||
AddStep("start stopwatch", () => stopwatch.Start());
|
||||
}
|
||||
|
||||
private static IEnumerable<DateTimeOffset> testCases => new[]
|
||||
{
|
||||
DateTimeOffset.Now,
|
||||
DateTimeOffset.Now.AddSeconds(-1),
|
||||
DateTimeOffset.Now.AddSeconds(-25),
|
||||
DateTimeOffset.Now.AddSeconds(-59),
|
||||
DateTimeOffset.Now.AddMinutes(-1),
|
||||
DateTimeOffset.Now.AddMinutes(-25),
|
||||
DateTimeOffset.Now.AddMinutes(-59),
|
||||
DateTimeOffset.Now.AddHours(-1),
|
||||
DateTimeOffset.Now.AddHours(-13),
|
||||
DateTimeOffset.Now.AddHours(-23),
|
||||
DateTimeOffset.Now.AddDays(-1),
|
||||
DateTimeOffset.Now.AddDays(-6),
|
||||
DateTimeOffset.Now.AddDays(-16),
|
||||
DateTimeOffset.Now.AddMonths(-1),
|
||||
DateTimeOffset.Now.AddMonths(-11),
|
||||
DateTimeOffset.Now.AddYears(-1),
|
||||
DateTimeOffset.Now.AddYears(-5)
|
||||
};
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -142,7 +143,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
modifiedBeatmap.HitObjects.Clear();
|
||||
modifiedBeatmap.HitObjects.Add(new HitCircle { StartTime = 5000 });
|
||||
|
||||
manager.Import(modifiedBeatmap.BeatmapInfo.BeatmapSet).Wait();
|
||||
manager.Import(modifiedBeatmap.BeatmapInfo.BeatmapSet).WaitSafely();
|
||||
});
|
||||
|
||||
// Create the room using the real beatmap values.
|
||||
@ -184,7 +185,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
},
|
||||
};
|
||||
|
||||
manager.Import(originalBeatmap.BeatmapInfo.BeatmapSet).Wait();
|
||||
manager.Import(originalBeatmap.BeatmapInfo.BeatmapSet).WaitSafely();
|
||||
});
|
||||
|
||||
AddUntilStep("match has correct beatmap", () => realHash == match.Beatmap.Value.BeatmapInfo.MD5Hash);
|
||||
@ -201,7 +202,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
});
|
||||
}
|
||||
|
||||
private void importBeatmap() => AddStep("import beatmap", () => importedBeatmap = manager.Import(CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Result);
|
||||
private void importBeatmap() => AddStep("import beatmap", () => importedBeatmap = manager.Import(CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).GetResultSafely());
|
||||
|
||||
private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
@ -74,7 +75,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep(@"Set beatmap", () =>
|
||||
{
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
|
||||
|
||||
leaderboard.BeatmapInfo = beatmapInfo;
|
||||
@ -175,7 +176,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep(@"Load new scores via manager", () =>
|
||||
{
|
||||
foreach (var score in generateSampleScores(beatmapInfo()))
|
||||
scoreManager.Import(score).Wait();
|
||||
scoreManager.Import(score).WaitSafely();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
@ -181,7 +182,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
beatmap.DifficultyName = $"SR{i + 1}";
|
||||
}
|
||||
|
||||
return Game.BeatmapManager.Import(beatmapSet).Result.Value;
|
||||
return Game.BeatmapManager.Import(beatmapSet).GetResultSafely().Value;
|
||||
}
|
||||
|
||||
private bool ensureAllBeatmapSetsImported(IEnumerable<BeatmapSetInfo> beatmapSets) => beatmapSets.All(set => set != null);
|
||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -38,7 +39,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, Audio, Resources, host, Beatmap.Default));
|
||||
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait();
|
||||
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
|
||||
|
||||
base.Content.AddRange(new Drawable[]
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
@ -256,7 +257,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("import multi-ruleset map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets)).Wait();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets)).WaitSafely();
|
||||
});
|
||||
}
|
||||
else
|
||||
@ -670,7 +671,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("import multi-ruleset map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).Wait();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).WaitSafely();
|
||||
});
|
||||
|
||||
int previousSetID = 0;
|
||||
@ -710,7 +711,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("import multi-ruleset map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).Wait();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).WaitSafely();
|
||||
});
|
||||
|
||||
DrawableCarouselBeatmapSet set = null;
|
||||
@ -759,7 +760,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("import huge difficulty count map", () =>
|
||||
{
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
|
||||
imported = manager.Import(TestResources.CreateTestBeatmapSetInfo(50, usableRulesets)).Result.Value;
|
||||
imported = manager.Import(TestResources.CreateTestBeatmapSetInfo(50, usableRulesets)).GetResultSafely().Value;
|
||||
});
|
||||
|
||||
AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First()));
|
||||
@ -868,7 +869,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
|
||||
|
||||
private void importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray())).Wait();
|
||||
private void importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray())).WaitSafely();
|
||||
|
||||
private void checkMusicPlaying(bool playing) =>
|
||||
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
|
||||
@ -898,7 +899,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(difficultyCountPerSet, usableRulesets)).Wait();
|
||||
manager.Import(TestResources.CreateTestBeatmapSetInfo(difficultyCountPerSet, usableRulesets)).WaitSafely();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
@ -85,7 +86,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
|
||||
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
|
||||
|
||||
beatmapInfo = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).Result.Value.Beatmaps[0];
|
||||
beatmapInfo = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely().Value.Beatmaps[0];
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
@ -101,7 +102,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
User = new APIUser { Username = "TestUser" },
|
||||
};
|
||||
|
||||
importedScores.Add(scoreManager.Import(score).Result.Value);
|
||||
importedScores.Add(scoreManager.Import(score).GetResultSafely().Value);
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
|
79
osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs
Normal file
79
osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs
Normal file
@ -0,0 +1,79 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface.PageSelector;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestScenePageSelector : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private OverlayColourProvider provider { get; } = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||
|
||||
private readonly PageSelector pageSelector;
|
||||
|
||||
public TestScenePageSelector()
|
||||
{
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
pageSelector = new PageSelector
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOmittedPages()
|
||||
{
|
||||
setAvailablePages(100);
|
||||
|
||||
selectPageIndex(0);
|
||||
checkVisiblePageNumbers(new[] { 1, 2, 3, 100 });
|
||||
|
||||
selectPageIndex(6);
|
||||
checkVisiblePageNumbers(new[] { 1, 5, 6, 7, 8, 9, 100 });
|
||||
|
||||
selectPageIndex(49);
|
||||
checkVisiblePageNumbers(new[] { 1, 48, 49, 50, 51, 52, 100 });
|
||||
|
||||
selectPageIndex(99);
|
||||
checkVisiblePageNumbers(new[] { 1, 98, 99, 100 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestResetCurrentPage()
|
||||
{
|
||||
setAvailablePages(10);
|
||||
selectPageIndex(6);
|
||||
setAvailablePages(11);
|
||||
AddAssert("Page 1 is current", () => pageSelector.CurrentPage.Value == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOutOfBoundsSelection()
|
||||
{
|
||||
setAvailablePages(10);
|
||||
selectPageIndex(11);
|
||||
AddAssert("Page 10 is current", () => pageSelector.CurrentPage.Value == pageSelector.AvailablePages.Value - 1);
|
||||
|
||||
selectPageIndex(-1);
|
||||
AddAssert("Page 1 is current", () => pageSelector.CurrentPage.Value == 0);
|
||||
}
|
||||
|
||||
private void checkVisiblePageNumbers(int[] expected) => AddAssert($"Sequence is {string.Join(',', expected.Select(i => i.ToString()))}", () => pageSelector.ChildrenOfType<PageSelectorPageButton>().Select(p => p.PageNumber).SequenceEqual(expected));
|
||||
|
||||
private void selectPageIndex(int pageIndex) =>
|
||||
AddStep($"Select page {pageIndex}", () => pageSelector.CurrentPage.Value = pageIndex);
|
||||
|
||||
private void setAvailablePages(int availablePages) =>
|
||||
AddStep($"Set available pages to {availablePages}", () => pageSelector.AvailablePages.Value = availablePages);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -31,7 +32,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
this.api = api;
|
||||
|
||||
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).Result;
|
||||
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).GetResultSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
TournamentStorage storage = (TournamentStorage)osu.Dependencies.Get<Storage>();
|
||||
FileBasedIPC ipc = null;
|
||||
|
||||
WaitForOrAssert(() => (ipc = osu.Dependencies.Get<MatchIPCInfo>() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time");
|
||||
WaitForOrAssert(() => (ipc = osu.Dependencies.Get<MatchIPCInfo>() as FileBasedIPC)?.IsLoaded == true, @"ipc could not be populated in a reasonable amount of time");
|
||||
|
||||
Assert.True(ipc.SetIPCLocation(testStableInstallDirectory));
|
||||
Assert.True(storage.AllTournaments.Exists("stable.json"));
|
||||
|
@ -93,8 +93,12 @@ namespace osu.Game.Beatmaps
|
||||
if (t.Time > lastTime)
|
||||
return (beatLength: t.BeatLength, 0);
|
||||
|
||||
// osu-stable forced the first control point to start at 0.
|
||||
// This is reproduced here to maintain compatibility around osu!mania scroll speed and song select display.
|
||||
double currentTime = i == 0 ? 0 : t.Time;
|
||||
double nextTime = i == ControlPointInfo.TimingPoints.Count - 1 ? lastTime : ControlPointInfo.TimingPoints[i + 1].Time;
|
||||
return (beatLength: t.BeatLength, duration: nextTime - t.Time);
|
||||
|
||||
return (beatLength: t.BeatLength, duration: nextTime - currentTime);
|
||||
})
|
||||
// Aggregate durations into a set of (beatLength, duration) tuples for each beat length
|
||||
.GroupBy(t => Math.Round(t.beatLength * 1000) / 1000)
|
||||
|
@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Lists;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
@ -261,13 +262,18 @@ namespace osu.Game.Beatmaps
|
||||
// GetDifficultyAsync will fall back to existing data from IBeatmapInfo if not locally available
|
||||
// (contrary to GetAsync)
|
||||
GetDifficultyAsync(bindable.BeatmapInfo, rulesetInfo, mods, cancellationToken)
|
||||
.ContinueWith(t =>
|
||||
.ContinueWith(task =>
|
||||
{
|
||||
// We're on a threadpool thread, but we should exit back to the update thread so consumers can safely handle value-changed events.
|
||||
Schedule(() =>
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested && t.Result != null)
|
||||
bindable.Value = t.Result;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var starDifficulty = task.GetResultSafely();
|
||||
|
||||
if (starDifficulty != null)
|
||||
bindable.Value = starDifficulty.Value;
|
||||
});
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
@ -91,7 +92,7 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
};
|
||||
|
||||
var imported = beatmapModelManager.Import(set).Result.Value;
|
||||
var imported = beatmapModelManager.Import(set).GetResultSafely().Value;
|
||||
|
||||
return GetWorkingBeatmap(imported.Beatmaps.First());
|
||||
}
|
||||
|
@ -3,16 +3,13 @@
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays;
|
||||
using osuTK;
|
||||
@ -156,54 +153,5 @@ namespace osu.Game.Beatmaps.Drawables.Cards
|
||||
Hollow = true,
|
||||
}, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private class ExpandedContentScrollContainer : OsuScrollContainer
|
||||
{
|
||||
public ExpandedContentScrollContainer()
|
||||
{
|
||||
ScrollbarVisible = false;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Height = Math.Min(Content.DrawHeight, 400);
|
||||
}
|
||||
|
||||
private bool allowScroll => !Precision.AlmostEquals(DrawSize, Content.DrawSize);
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return false;
|
||||
|
||||
return base.OnDragStart(e);
|
||||
}
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return;
|
||||
|
||||
base.OnDrag(e);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return;
|
||||
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
|
||||
protected override bool OnScroll(ScrollEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return false;
|
||||
|
||||
return base.OnScroll(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
// 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.Input.Events;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables.Cards
|
||||
{
|
||||
public class ExpandedContentScrollContainer : OsuScrollContainer
|
||||
{
|
||||
public const float HEIGHT = 200;
|
||||
|
||||
public ExpandedContentScrollContainer()
|
||||
{
|
||||
ScrollbarVisible = false;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Height = Math.Min(Content.DrawHeight, HEIGHT);
|
||||
}
|
||||
|
||||
private bool allowScroll => !Precision.AlmostEquals(DrawSize, Content.DrawSize);
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return false;
|
||||
|
||||
return base.OnDragStart(e);
|
||||
}
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return;
|
||||
|
||||
base.OnDrag(e);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return;
|
||||
|
||||
base.OnDragEnd(e);
|
||||
}
|
||||
|
||||
protected override bool OnScroll(ScrollEvent e)
|
||||
{
|
||||
if (!allowScroll)
|
||||
return false;
|
||||
|
||||
return base.OnScroll(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Testing;
|
||||
@ -185,7 +186,7 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
try
|
||||
{
|
||||
return loadBeatmapAsync().Result;
|
||||
return loadBeatmapAsync().GetResultSafely();
|
||||
}
|
||||
catch (AggregateException ae)
|
||||
{
|
||||
|
@ -98,6 +98,8 @@ namespace osu.Game.Configuration
|
||||
SetDefault(OsuSetting.MenuParallax, true);
|
||||
|
||||
// Gameplay
|
||||
SetDefault(OsuSetting.PositionalHitsounds, true); // replaced by level setting below, can be removed 20220703.
|
||||
SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1);
|
||||
SetDefault(OsuSetting.DimLevel, 0.8, 0, 1, 0.01);
|
||||
SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
|
||||
SetDefault(OsuSetting.LightenDuringBreaks, true);
|
||||
@ -109,7 +111,6 @@ namespace osu.Game.Configuration
|
||||
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
||||
SetDefault(OsuSetting.KeyOverlay, false);
|
||||
SetDefault(OsuSetting.PositionalHitSounds, true);
|
||||
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
||||
|
||||
SetDefault(OsuSetting.FloatingComments, false);
|
||||
@ -175,9 +176,11 @@ namespace osu.Game.Configuration
|
||||
|
||||
int combined = (year * 10000) + monthDay;
|
||||
|
||||
if (combined < 20210413)
|
||||
if (combined < 20220103)
|
||||
{
|
||||
SetValue(OsuSetting.EditorWaveformOpacity, 0.25f);
|
||||
var positionalHitsoundsEnabled = GetBindable<bool>(OsuSetting.PositionalHitsounds);
|
||||
if (!positionalHitsoundsEnabled.Value)
|
||||
SetValue(OsuSetting.PositionalHitsoundsLevel, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,7 +259,8 @@ namespace osu.Game.Configuration
|
||||
LightenDuringBreaks,
|
||||
ShowStoryboard,
|
||||
KeyOverlay,
|
||||
PositionalHitSounds,
|
||||
PositionalHitsounds,
|
||||
PositionalHitsoundsLevel,
|
||||
AlwaysPlayFirstComboBreak,
|
||||
FloatingComments,
|
||||
HUDVisibilityMode,
|
||||
|
@ -8,6 +8,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Online.API;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@ -58,7 +59,7 @@ namespace osu.Game.Database
|
||||
if (!task.IsCompletedSuccessfully)
|
||||
return null;
|
||||
|
||||
return task.Result;
|
||||
return task.GetResultSafely();
|
||||
}, token));
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,9 @@ namespace osu.Game.Database
|
||||
/// <summary>
|
||||
/// Create a detached copy of the each item in the collection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Items which are already detached (ie. not managed by realm) will not be modified.
|
||||
/// </remarks>
|
||||
/// <param name="items">A list of managed <see cref="RealmObject"/>s to detach.</param>
|
||||
/// <typeparam name="T">The type of object.</typeparam>
|
||||
/// <returns>A list containing non-managed copies of provided items.</returns>
|
||||
@ -42,6 +45,9 @@ namespace osu.Game.Database
|
||||
/// <summary>
|
||||
/// Create a detached copy of the item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the item if already detached (ie. not managed by realm) it will not be detached again and the original instance will be returned. This allows this method to be potentially called at multiple levels while only incurring the clone overhead once.
|
||||
/// </remarks>
|
||||
/// <param name="item">The managed <see cref="RealmObject"/> to detach.</param>
|
||||
/// <typeparam name="T">The type of object.</typeparam>
|
||||
/// <returns>A non-managed copy of provided item. Will return the provided item if already detached.</returns>
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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.Globalization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Online.API.Requests;
|
||||
@ -16,7 +18,7 @@ namespace osu.Game.Extensions
|
||||
{
|
||||
cursor?.Properties.ForEach(x =>
|
||||
{
|
||||
webRequest.AddParameter("cursor[" + x.Key + "]", x.Value.ToString());
|
||||
webRequest.AddParameter("cursor[" + x.Key + "]", (x.Value as JValue)?.ToString(CultureInfo.InvariantCulture) ?? x.Value.ToString());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -17,8 +18,6 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
/// </summary>
|
||||
public class Background : CompositeDrawable, IEquatable<Background>
|
||||
{
|
||||
private const float blur_scale = 0.5f;
|
||||
|
||||
public readonly Sprite Sprite;
|
||||
|
||||
private readonly string textureName;
|
||||
@ -46,7 +45,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
Sprite.Texture = textures.Get(textureName);
|
||||
}
|
||||
|
||||
public Vector2 BlurSigma => bufferedContainer?.BlurSigma / blur_scale ?? Vector2.Zero;
|
||||
public Vector2 BlurSigma => Vector2.Divide(bufferedContainer?.BlurSigma ?? Vector2.Zero, blurScale);
|
||||
|
||||
/// <summary>
|
||||
/// Smoothly adjusts <see cref="IBufferedContainer.BlurSigma"/> over time.
|
||||
@ -67,9 +66,48 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
}
|
||||
|
||||
if (bufferedContainer != null)
|
||||
bufferedContainer.FrameBufferScale = newBlurSigma == Vector2.Zero ? Vector2.One : new Vector2(blur_scale);
|
||||
transformBlurSigma(newBlurSigma, duration, easing);
|
||||
}
|
||||
|
||||
bufferedContainer?.BlurTo(newBlurSigma * blur_scale, duration, easing);
|
||||
private void transformBlurSigma(Vector2 newBlurSigma, double duration, Easing easing)
|
||||
=> this.TransformTo(nameof(blurSigma), newBlurSigma, duration, easing);
|
||||
|
||||
private Vector2 blurSigmaBacking = Vector2.Zero;
|
||||
private Vector2 blurScale = Vector2.One;
|
||||
|
||||
private Vector2 blurSigma
|
||||
{
|
||||
get => blurSigmaBacking;
|
||||
set
|
||||
{
|
||||
Debug.Assert(bufferedContainer != null);
|
||||
|
||||
blurSigmaBacking = value;
|
||||
blurScale = new Vector2(calculateBlurDownscale(value.X), calculateBlurDownscale(value.Y));
|
||||
|
||||
bufferedContainer.FrameBufferScale = blurScale;
|
||||
bufferedContainer.BlurSigma = value * blurScale; // If the image is scaled down, the blur radius also needs to be reduced to cover the same pixel block.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a factor to downscale the background based on a given blur sigma, in order to reduce the computational complexity of blurs.
|
||||
/// </summary>
|
||||
/// <param name="sigma">The blur sigma.</param>
|
||||
/// <returns>The scale-down factor.</returns>
|
||||
private float calculateBlurDownscale(float sigma)
|
||||
{
|
||||
// If we're blurring within one pixel, scaling down will always result in an undesirable loss of quality.
|
||||
// The algorithm below would also cause this value to go above 1, which is likewise undesirable.
|
||||
if (sigma <= 1)
|
||||
return 1;
|
||||
|
||||
// A good value is one where the loss in quality as a result of downscaling the image is not easily perceivable.
|
||||
// The constants here have been experimentally chosen to yield nice transitions by approximating a log curve through the points {{ 1, 1 }, { 4, 0.75 }, { 16, 0.5 }, { 32, 0.25 }}.
|
||||
float scale = -0.18f * MathF.Log(0.004f * sigma);
|
||||
|
||||
// To reduce shimmering, the scaling transitions are limited to happen only in increments of 0.2.
|
||||
return MathF.Round(scale / 0.2f, MidpointRounding.AwayFromZero) * 0.2f;
|
||||
}
|
||||
|
||||
public virtual bool Equals(Background other)
|
||||
|
@ -1,20 +1,29 @@
|
||||
// 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 enable
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
|
||||
namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
public class BeatmapBackgroundWithStoryboard : BeatmapBackground
|
||||
{
|
||||
private readonly InterpolatingFramedClock storyboardClock;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private MusicController? musicController { get; set; }
|
||||
|
||||
public BeatmapBackgroundWithStoryboard(WorkingBeatmap beatmap, string fallbackTextureName = "Backgrounds/bg1")
|
||||
: base(beatmap, fallbackTextureName)
|
||||
{
|
||||
storyboardClock = new InterpolatingFramedClock();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -30,8 +39,40 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Volume = { Value = 0 },
|
||||
Child = new DrawableStoryboard(Beatmap.Storyboard) { Clock = new InterpolatingFramedClock(Beatmap.Track) }
|
||||
Child = new DrawableStoryboard(Beatmap.Storyboard) { Clock = storyboardClock }
|
||||
}, AddInternal);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
if (musicController != null)
|
||||
musicController.TrackChanged += onTrackChanged;
|
||||
|
||||
updateStoryboardClockSource(Beatmap);
|
||||
}
|
||||
|
||||
private void onTrackChanged(WorkingBeatmap newBeatmap, TrackChangeDirection _) => updateStoryboardClockSource(newBeatmap);
|
||||
|
||||
private void updateStoryboardClockSource(WorkingBeatmap newBeatmap)
|
||||
{
|
||||
if (newBeatmap != Beatmap)
|
||||
return;
|
||||
|
||||
// `MusicController` will sometimes reload the track, even when the working beatmap technically hasn't changed.
|
||||
// ensure that the storyboard's clock is always using the latest track instance.
|
||||
storyboardClock.ChangeSource(newBeatmap.Track);
|
||||
// more often than not, the previous source track's time will be in the future relative to the new source track.
|
||||
// explicitly process a single frame so that `InterpolatingFramedClock`'s interpolation logic is bypassed
|
||||
// and the storyboard clock is correctly rewound to the source track's time exactly.
|
||||
storyboardClock.ProcessFrame();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
if (musicController != null)
|
||||
musicController.TrackChanged -= onTrackChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs
Normal file
33
osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||
{
|
||||
internal class PageEllipsis : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||
Text = "...",
|
||||
Colour = colourProvider.Light3,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
102
osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs
Normal file
102
osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs
Normal file
@ -0,0 +1,102 @@
|
||||
// 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.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||
{
|
||||
public class PageSelector : CompositeDrawable
|
||||
{
|
||||
public readonly BindableInt CurrentPage = new BindableInt { MinValue = 0, };
|
||||
|
||||
public readonly BindableInt AvailablePages = new BindableInt(1) { MinValue = 1, };
|
||||
|
||||
private readonly FillFlowContainer itemsFlow;
|
||||
|
||||
private readonly PageSelectorPrevNextButton previousPageButton;
|
||||
private readonly PageSelectorPrevNextButton nextPageButton;
|
||||
|
||||
public PageSelector()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
previousPageButton = new PageSelectorPrevNextButton(false, "prev")
|
||||
{
|
||||
Action = () => CurrentPage.Value -= 1,
|
||||
},
|
||||
itemsFlow = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
},
|
||||
nextPageButton = new PageSelectorPrevNextButton(true, "next")
|
||||
{
|
||||
Action = () => CurrentPage.Value += 1
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
CurrentPage.BindValueChanged(_ => Scheduler.AddOnce(redraw));
|
||||
AvailablePages.BindValueChanged(_ =>
|
||||
{
|
||||
CurrentPage.Value = 0;
|
||||
|
||||
// AddOnce as the reset of CurrentPage may also trigger a redraw.
|
||||
Scheduler.AddOnce(redraw);
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void redraw()
|
||||
{
|
||||
if (CurrentPage.Value >= AvailablePages.Value)
|
||||
{
|
||||
CurrentPage.Value = AvailablePages.Value - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
previousPageButton.Enabled.Value = CurrentPage.Value != 0;
|
||||
nextPageButton.Enabled.Value = CurrentPage.Value < AvailablePages.Value - 1;
|
||||
|
||||
itemsFlow.Clear();
|
||||
|
||||
int totalPages = AvailablePages.Value;
|
||||
bool lastWasEllipsis = false;
|
||||
|
||||
for (int i = 0; i < totalPages; i++)
|
||||
{
|
||||
int pageIndex = i;
|
||||
|
||||
bool shouldShowPage = pageIndex == 0 || pageIndex == totalPages - 1 || Math.Abs(pageIndex - CurrentPage.Value) <= 2;
|
||||
|
||||
if (shouldShowPage)
|
||||
{
|
||||
lastWasEllipsis = false;
|
||||
itemsFlow.Add(new PageSelectorPageButton(pageIndex + 1)
|
||||
{
|
||||
Action = () => CurrentPage.Value = pageIndex,
|
||||
Selected = CurrentPage.Value == pageIndex,
|
||||
});
|
||||
}
|
||||
else if (!lastWasEllipsis)
|
||||
{
|
||||
lastWasEllipsis = true;
|
||||
itemsFlow.Add(new PageEllipsis());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
// 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.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||
{
|
||||
public abstract class PageSelectorButton : OsuClickableContainer
|
||||
{
|
||||
protected const int DURATION = 200;
|
||||
|
||||
[Resolved]
|
||||
protected OverlayColourProvider ColourProvider { get; private set; }
|
||||
|
||||
protected Box Background;
|
||||
|
||||
protected PageSelectorButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.X;
|
||||
Height = 20;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Masking = true,
|
||||
Children = new[]
|
||||
{
|
||||
Background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
CreateContent().With(content =>
|
||||
{
|
||||
content.Anchor = Anchor.Centre;
|
||||
content.Origin = Anchor.Centre;
|
||||
content.Margin = new MarginPadding { Horizontal = 10 };
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
protected abstract Drawable CreateContent();
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
UpdateHoverState();
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
base.OnHoverLost(e);
|
||||
UpdateHoverState();
|
||||
}
|
||||
|
||||
protected abstract void UpdateHoverState();
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
// 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.Framework.Bindables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||
{
|
||||
public class PageSelectorPageButton : PageSelectorButton
|
||||
{
|
||||
private readonly BindableBool selected = new BindableBool();
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
set => selected.Value = value;
|
||||
}
|
||||
|
||||
public int PageNumber { get; }
|
||||
|
||||
private OsuSpriteText text;
|
||||
|
||||
public PageSelectorPageButton(int pageNumber)
|
||||
{
|
||||
PageNumber = pageNumber;
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
if (!selected.Value)
|
||||
selected.Value = true;
|
||||
};
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||
Text = PageNumber.ToString(),
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Background.Colour = ColourProvider.Highlight1;
|
||||
Background.Alpha = 0;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
selected.BindValueChanged(onSelectedChanged, true);
|
||||
}
|
||||
|
||||
private void onSelectedChanged(ValueChangedEvent<bool> selected)
|
||||
{
|
||||
Background.FadeTo(selected.NewValue ? 1 : 0, DURATION, Easing.OutQuint);
|
||||
|
||||
text.FadeColour(selected.NewValue ? ColourProvider.Dark4 : ColourProvider.Light3, DURATION, Easing.OutQuint);
|
||||
text.Font = text.Font.With(weight: IsHovered ? FontWeight.SemiBold : FontWeight.Regular);
|
||||
}
|
||||
|
||||
protected override void UpdateHoverState()
|
||||
{
|
||||
if (selected.Value)
|
||||
return;
|
||||
|
||||
text.FadeColour(IsHovered ? ColourProvider.Light2 : ColourProvider.Light1, DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
// 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.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface.PageSelector
|
||||
{
|
||||
public class PageSelectorPrevNextButton : PageSelectorButton
|
||||
{
|
||||
private readonly bool rightAligned;
|
||||
private readonly string text;
|
||||
|
||||
private SpriteIcon icon;
|
||||
private OsuSpriteText name;
|
||||
|
||||
public PageSelectorPrevNextButton(bool rightAligned, string text)
|
||||
{
|
||||
this.rightAligned = rightAligned;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
name = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||
Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||
Text = text.ToUpper(),
|
||||
},
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Icon = rightAligned ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft,
|
||||
Size = new Vector2(8),
|
||||
Anchor = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||
Origin = rightAligned ? Anchor.CentreLeft : Anchor.CentreRight,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Background.Colour = ColourProvider.Dark4;
|
||||
name.Colour = icon.Colour = ColourProvider.Light1;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Enabled.BindValueChanged(enabled => Background.FadeTo(enabled.NewValue ? 1 : 0.5f, DURATION), true);
|
||||
}
|
||||
|
||||
protected override void UpdateHoverState() =>
|
||||
Background.FadeColour(IsHovered ? ColourProvider.Dark3 : ColourProvider.Dark4, DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
@ -32,7 +32,18 @@ namespace osu.Game.IO.Archives
|
||||
|
||||
public abstract IEnumerable<string> Filenames { get; }
|
||||
|
||||
public virtual byte[] Get(string name) => GetAsync(name).Result;
|
||||
public virtual byte[] Get(string name)
|
||||
{
|
||||
using (Stream input = GetStream(name))
|
||||
{
|
||||
if (input == null)
|
||||
return null;
|
||||
|
||||
byte[] buffer = new byte[input.Length];
|
||||
input.Read(buffer);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetAsync(string name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
@ -77,6 +77,8 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight),
|
||||
new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode),
|
||||
new KeyBinding(new[] { InputKey.F5 }, GlobalAction.EditorTestGameplay),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.H }, GlobalAction.EditorFlipHorizontally),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.J }, GlobalAction.EditorFlipVertically),
|
||||
};
|
||||
|
||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||
@ -292,6 +294,12 @@ namespace osu.Game.Input.Bindings
|
||||
EditorCycleGridDisplayMode,
|
||||
|
||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTestGameplay))]
|
||||
EditorTestGameplay
|
||||
EditorTestGameplay,
|
||||
|
||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorFlipHorizontally))]
|
||||
EditorFlipHorizontally,
|
||||
|
||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorFlipVertically))]
|
||||
EditorFlipVertically,
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
// 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.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Input
|
||||
@ -63,8 +65,17 @@ namespace osu.Game.Input
|
||||
|
||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) => updateLastInteractionTime();
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
protected override bool Handle(UIEvent e)
|
||||
{
|
||||
// Even when not active, `MouseMoveEvent`s will arrive.
|
||||
// We don't want these to trigger a non-idle state as it's quite often the user interacting
|
||||
// with other windows while osu! is in the background.
|
||||
if (!host.IsActive.Value)
|
||||
return base.Handle(e);
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case KeyDownEvent _:
|
||||
|
@ -32,6 +32,11 @@ namespace osu.Game.Localisation
|
||||
/// <summary>
|
||||
/// "Master"
|
||||
/// </summary>
|
||||
public static LocalisableString PositionalLevel => new TranslatableString(getKey(@"positional_hitsound_audio_level"), @"Hitsound stereo separation");
|
||||
|
||||
/// <summary>
|
||||
/// "Level"
|
||||
/// </summary>
|
||||
public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master");
|
||||
|
||||
/// <summary>
|
||||
|
@ -44,6 +44,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches");
|
||||
|
||||
/// <summary>
|
||||
/// "Compact realm"
|
||||
/// </summary>
|
||||
public static LocalisableString CompactRealm => new TranslatableString(getKey(@"compact_realm"), @"Compact realm");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
@ -84,11 +84,6 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay");
|
||||
|
||||
/// <summary>
|
||||
/// "Positional hitsounds"
|
||||
/// </summary>
|
||||
public static LocalisableString PositionalHitsounds => new TranslatableString(getKey(@"positional_hitsounds"), @"Positional hitsounds");
|
||||
|
||||
/// <summary>
|
||||
/// "Always play first combo break sound"
|
||||
/// </summary>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user