mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 05:39:53 +08:00
Compare commits
595 Commits
2021.815.0
...
2021.828.0
+2
-2
@@ -51,8 +51,8 @@
|
||||
<Reference Include="Java.Interop" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.813.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.813.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.827.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.828.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. -->
|
||||
|
||||
@@ -20,8 +20,21 @@ namespace osu.Android
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance, Exported = true)]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-archive")]
|
||||
[IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream", "application/download", "application/x-zip", "application/x-zip-compressed", "application/x-osu-archive" })]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-beatmap-archive")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-skin-archive")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")]
|
||||
[IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[]
|
||||
{
|
||||
"application/zip",
|
||||
"application/octet-stream",
|
||||
"application/download",
|
||||
"application/x-zip",
|
||||
"application/x-zip-compressed",
|
||||
// newer official mime types (see https://osu.ppy.sh/wiki/en/osu%21_File_Formats).
|
||||
"application/x-osu-beatmap-archive",
|
||||
"application/x-osu-skin-archive",
|
||||
"application/x-osu-replay",
|
||||
})]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })]
|
||||
public class OsuGameActivity : AndroidGameActivity
|
||||
{
|
||||
@@ -66,12 +79,14 @@ namespace osu.Android
|
||||
case Intent.ActionSendMultiple:
|
||||
{
|
||||
var uris = new List<Uri>();
|
||||
|
||||
for (int i = 0; i < intent.ClipData?.ItemCount; i++)
|
||||
{
|
||||
var content = intent.ClipData?.GetItemAt(i);
|
||||
if (content != null)
|
||||
uris.Add(content.Uri);
|
||||
}
|
||||
|
||||
handleImportFromUris(uris.ToArray());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ namespace osu.Desktop
|
||||
{
|
||||
switch (activity)
|
||||
{
|
||||
case UserActivity.SoloGame solo:
|
||||
return solo.Beatmap.ToString();
|
||||
case UserActivity.InGame game:
|
||||
return game.Beatmap.ToString();
|
||||
|
||||
case UserActivity.Editing edit:
|
||||
return edit.Beatmap.ToString();
|
||||
|
||||
@@ -5,23 +5,23 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Desktop.Windows
|
||||
{
|
||||
public class GameplayWinKeyBlocker : Component
|
||||
{
|
||||
private Bindable<bool> disableWinKey;
|
||||
private Bindable<bool> localUserPlaying;
|
||||
private IBindable<bool> localUserPlaying;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGame game, OsuConfigManager config)
|
||||
private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config)
|
||||
{
|
||||
localUserPlaying = game.LocalUserPlaying.GetBoundCopy();
|
||||
localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
|
||||
localUserPlaying.BindValueChanged(_ => updateBlocking());
|
||||
|
||||
disableWinKey = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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 BenchmarkDotNet.Attributes;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
|
||||
namespace osu.Game.Benchmarks
|
||||
{
|
||||
public class BenchmarkMod : BenchmarkTest
|
||||
{
|
||||
private OsuModDoubleTime mod;
|
||||
|
||||
[Params(1, 10, 100)]
|
||||
public int Times { get; set; }
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
{
|
||||
mod = new OsuModDoubleTime();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int ModHashCode()
|
||||
{
|
||||
var hashCode = new HashCode();
|
||||
|
||||
for (int i = 0; i < Times; i++)
|
||||
hashCode.Add(mod);
|
||||
|
||||
return hashCode.ToHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,9 +210,9 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor
|
||||
new Vector2(50, 200),
|
||||
}), 0.5);
|
||||
AddAssert("1 vertex per 1 nested HO", () => getVertices().Count == hitObject.NestedHitObjects.Count);
|
||||
AddAssert("slider path not yet changed", () => hitObject.Path.ControlPoints[0].Type.Value == PathType.PerfectCurve);
|
||||
AddAssert("slider path not yet changed", () => hitObject.Path.ControlPoints[0].Type == PathType.PerfectCurve);
|
||||
addAddVertexSteps(150, 150);
|
||||
AddAssert("slider path change to linear", () => hitObject.Path.ControlPoints[0].Type.Value == PathType.Linear);
|
||||
AddAssert("slider path change to linear", () => hitObject.Path.ControlPoints[0].Type == PathType.Linear);
|
||||
}
|
||||
|
||||
private void addBlueprintStep(double time, float x, SliderPath sliderPath, double velocity) => AddStep("add selection blueprint", () =>
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
} while (rng.Next(2) != 0);
|
||||
|
||||
int length = sliderPath.ControlPoints.Count - start + 1;
|
||||
sliderPath.ControlPoints[start].Type.Value = length <= 2 ? PathType.Linear : length == 3 ? PathType.PerfectCurve : PathType.Bezier;
|
||||
sliderPath.ControlPoints[start].Type = length <= 2 ? PathType.Linear : length == 3 ? PathType.PerfectCurve : PathType.Bezier;
|
||||
} while (rng.Next(3) != 0);
|
||||
|
||||
if (rng.Next(5) == 0)
|
||||
@@ -210,13 +210,13 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
|
||||
path.ConvertToSliderPath(sliderPath, sliderStartY);
|
||||
Assert.That(sliderPath.Distance, Is.EqualTo(path.Distance).Within(1e-3));
|
||||
Assert.That(sliderPath.ControlPoints[0].Position.Value.X, Is.EqualTo(path.Vertices[0].X));
|
||||
Assert.That(sliderPath.ControlPoints[0].Position.X, Is.EqualTo(path.Vertices[0].X));
|
||||
assertInvariants(path.Vertices, true);
|
||||
|
||||
foreach (var point in sliderPath.ControlPoints)
|
||||
{
|
||||
Assert.That(point.Type.Value, Is.EqualTo(PathType.Linear).Or.Null);
|
||||
Assert.That(sliderStartY + point.Position.Value.Y, Is.InRange(0, JuiceStreamPath.OSU_PLAYFIELD_HEIGHT));
|
||||
Assert.That(point.Type, Is.EqualTo(PathType.Linear).Or.Null);
|
||||
Assert.That(sliderStartY + point.Position.Y, Is.InRange(0, JuiceStreamPath.OSU_PLAYFIELD_HEIGHT));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||
|
||||
case JuiceStream juiceStream:
|
||||
// Todo: BUG!! Stable used the last control point as the final position of the path, but it should use the computed path instead.
|
||||
lastPosition = juiceStream.OriginalX + juiceStream.Path.ControlPoints[^1].Position.Value.X;
|
||||
lastPosition = juiceStream.OriginalX + juiceStream.Path.ControlPoints[^1].Position.X;
|
||||
|
||||
// Todo: BUG!! Stable attempted to use the end time of the stream, but referenced it too early in execution and used the start time instead.
|
||||
lastStartTime = juiceStream.StartTime;
|
||||
|
||||
@@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Difficulty.Skills
|
||||
{
|
||||
public class Movement : StrainSkill
|
||||
public class Movement : StrainDecaySkill
|
||||
{
|
||||
private const float absolute_player_positioning_error = 16f;
|
||||
private const float normalized_hitobject_radius = 41.0f;
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components
|
||||
path.ConvertFromSliderPath(sliderPath);
|
||||
|
||||
// If the original slider path has non-linear type segments, resample the vertices at nested hit object times to reduce the number of vertices.
|
||||
if (sliderPath.ControlPoints.Any(p => p.Type.Value != null && p.Type.Value != PathType.Linear))
|
||||
if (sliderPath.ControlPoints.Any(p => p.Type != null && p.Type != PathType.Linear))
|
||||
{
|
||||
path.ResampleVertices(hitObject.NestedHitObjects
|
||||
.Skip(1).TakeWhile(h => !(h is Fruit)) // Only droplets in the first span are used.
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Catch.Edit
|
||||
juiceStream.OriginalX = selectionRange.GetFlippedPosition(juiceStream.OriginalX);
|
||||
|
||||
foreach (var point in juiceStream.Path.ControlPoints)
|
||||
point.Position.Value *= new Vector2(-1, 1);
|
||||
point.Position *= new Vector2(-1, 1);
|
||||
|
||||
EditorBeatmap.Update(juiceStream);
|
||||
return true;
|
||||
|
||||
@@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
/// </summary>
|
||||
private static void mirrorJuiceStreamPath(JuiceStream juiceStream)
|
||||
{
|
||||
var controlPoints = juiceStream.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||
var controlPoints = juiceStream.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray();
|
||||
foreach (var point in controlPoints)
|
||||
point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y);
|
||||
point.Position = new Vector2(-point.Position.X, point.Position.Y);
|
||||
|
||||
juiceStream.Path = new SliderPath(controlPoints, juiceStream.Path.ExpectedDistance.Value);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position.Value, c.Type.Value)));
|
||||
path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position, c.Type)));
|
||||
path.ExpectedDistance.Value = value.ExpectedDistance.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
|
||||
for (int i = 1; i < vertices.Count; i++)
|
||||
{
|
||||
sliderPath.ControlPoints[^1].Type.Value = PathType.Linear;
|
||||
sliderPath.ControlPoints[^1].Type = PathType.Linear;
|
||||
|
||||
float deltaX = vertices[i].X - lastPosition.X;
|
||||
double length = vertices[i].Distance - currentDistance;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Compose;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||
{
|
||||
public class TestSceneManiaComposeScreen : EditorClockTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private SkinManager skins { get; set; }
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("setup compose screen", () =>
|
||||
{
|
||||
var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }))
|
||||
{
|
||||
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
|
||||
};
|
||||
|
||||
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
||||
|
||||
Child = new DependencyProvidingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CachedDependencies = new (Type, object)[]
|
||||
{
|
||||
(typeof(EditorBeatmap), editorBeatmap),
|
||||
(typeof(IBeatSnapProvider), editorBeatmap),
|
||||
},
|
||||
Child = new ComposeScreen { State = { Value = Visibility.Visible } },
|
||||
};
|
||||
});
|
||||
|
||||
AddUntilStep("wait for composer", () => this.ChildrenOfType<HitObjectComposer>().SingleOrDefault()?.IsLoaded == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDefaultSkin()
|
||||
{
|
||||
AddStep("set default skin", () => skins.CurrentSkinInfo.Value = SkinInfo.Default);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLegacySkin()
|
||||
{
|
||||
AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
||||
{
|
||||
public class Strain : StrainSkill
|
||||
public class Strain : StrainDecaySkill
|
||||
{
|
||||
private const double individual_decay_base = 0.125;
|
||||
private const double overall_decay_base = 0.30;
|
||||
@@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
|
||||
return individualStrain + overallStrain - CurrentStrain;
|
||||
}
|
||||
|
||||
protected override double GetPeakStrain(double offset)
|
||||
protected override double CalculateInitialStrain(double offset)
|
||||
=> applyDecay(individualStrain, offset - Previous[0].StartTime, individual_decay_base)
|
||||
+ applyDecay(overallStrain, offset - Previous[0].StartTime, overall_decay_base);
|
||||
|
||||
|
||||
@@ -275,9 +275,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
return false;
|
||||
|
||||
beginHoldAt(Time.Current - Head.HitObject.StartTime);
|
||||
Head.UpdateResult();
|
||||
|
||||
return true;
|
||||
return Head.UpdateResult();
|
||||
}
|
||||
|
||||
private void beginHoldAt(double timeOffset)
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
Origin = Anchor.TopCentre;
|
||||
}
|
||||
|
||||
public void UpdateResult() => base.UpdateResult(true);
|
||||
public bool UpdateResult() => base.UpdateResult(true);
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
|
||||
AddAssert("last connection displayed", () =>
|
||||
{
|
||||
var lastConnection = visualiser.Connections.Last(c => c.ControlPoint.Position.Value == new Vector2(300));
|
||||
var lastConnection = visualiser.Connections.Last(c => c.ControlPoint.Position == new Vector2(300));
|
||||
return lastConnection.DrawWidth > 50;
|
||||
});
|
||||
}
|
||||
@@ -166,14 +166,14 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
{
|
||||
AddStep($"move mouse to control point {index}", () =>
|
||||
{
|
||||
Vector2 position = slider.Path.ControlPoints[index].Position.Value;
|
||||
Vector2 position = slider.Path.ControlPoints[index].Position;
|
||||
InputManager.MoveMouseTo(visualiser.Pieces[0].Parent.ToScreenSpace(position));
|
||||
});
|
||||
}
|
||||
|
||||
private void assertControlPointPathType(int controlPointIndex, PathType? type)
|
||||
{
|
||||
AddAssert($"point {controlPointIndex} is {type}", () => slider.Path.ControlPoints[controlPointIndex].Type.Value == type);
|
||||
AddAssert($"point {controlPointIndex} is {type}", () => slider.Path.ControlPoints[controlPointIndex].Type == type);
|
||||
}
|
||||
|
||||
private void addContextMenuItemStep(string contextMenuText)
|
||||
|
||||
@@ -108,9 +108,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
[Test]
|
||||
public void TestDragControlPointPathAfterChangingType()
|
||||
{
|
||||
AddStep("change type to bezier", () => slider.Path.ControlPoints[2].Type.Value = PathType.Bezier);
|
||||
AddStep("change type to bezier", () => slider.Path.ControlPoints[2].Type = PathType.Bezier);
|
||||
AddStep("add point", () => slider.Path.ControlPoints.Add(new PathControlPoint(new Vector2(500, 10))));
|
||||
AddStep("change type to perfect", () => slider.Path.ControlPoints[3].Type.Value = PathType.PerfectCurve);
|
||||
AddStep("change type to perfect", () => slider.Path.ControlPoints[3].Type = PathType.PerfectCurve);
|
||||
|
||||
moveMouseToControlPoint(4);
|
||||
AddStep("hold", () => InputManager.PressButton(MouseButton.Left));
|
||||
@@ -137,15 +137,15 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
{
|
||||
AddStep($"move mouse to control point {index}", () =>
|
||||
{
|
||||
Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position.Value;
|
||||
Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position;
|
||||
InputManager.MoveMouseTo(drawableObject.Parent.ToScreenSpace(position));
|
||||
});
|
||||
}
|
||||
|
||||
private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => slider.Path.ControlPoints[index].Type.Value == type);
|
||||
private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => slider.Path.ControlPoints[index].Type == type);
|
||||
|
||||
private void assertControlPointPosition(int index, Vector2 position) =>
|
||||
AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, slider.Path.ControlPoints[index].Position.Value, 1));
|
||||
AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, slider.Path.ControlPoints[index].Position, 1));
|
||||
|
||||
private class TestSliderBlueprint : SliderSelectionBlueprint
|
||||
{
|
||||
|
||||
@@ -385,10 +385,10 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
|
||||
private void assertControlPointCount(int expected) => AddAssert($"has {expected} control points", () => getSlider().Path.ControlPoints.Count == expected);
|
||||
|
||||
private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => getSlider().Path.ControlPoints[index].Type.Value == type);
|
||||
private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => getSlider().Path.ControlPoints[index].Type == type);
|
||||
|
||||
private void assertControlPointPosition(int index, Vector2 position) =>
|
||||
AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, getSlider().Path.ControlPoints[index].Position.Value, 1));
|
||||
AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, getSlider().Path.ControlPoints[index].Position, 1));
|
||||
|
||||
private Slider getSlider() => HitObjectContainer.Count > 0 ? ((DrawableSlider)HitObjectContainer[0]).HitObject : null;
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
{
|
||||
AddStep($"move mouse to control point {index}", () =>
|
||||
{
|
||||
Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position.Value;
|
||||
Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position;
|
||||
InputManager.MoveMouseTo(drawableObject.Parent.ToScreenSpace(position));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using osu.Framework.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
{
|
||||
public abstract class OsuStrainSkill : StrainSkill
|
||||
public abstract class OsuStrainSkill : StrainDecaySkill
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of sections with the highest strains, which the peak strain reductions will apply to.
|
||||
|
||||
+2
-2
@@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
/// </summary>
|
||||
private void updateConnectingPath()
|
||||
{
|
||||
Position = slider.StackedPosition + ControlPoint.Position.Value;
|
||||
Position = slider.StackedPosition + ControlPoint.Position;
|
||||
|
||||
path.ClearVertices();
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
return;
|
||||
|
||||
path.AddVertex(Vector2.Zero);
|
||||
path.AddVertex(slider.Path.ControlPoints[nextIndex].Position.Value - ControlPoint.Position.Value);
|
||||
path.AddVertex(slider.Path.ControlPoints[nextIndex].Position - ControlPoint.Position);
|
||||
|
||||
path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
private IBindable<Vector2> sliderPosition;
|
||||
private IBindable<float> sliderScale;
|
||||
private IBindable<Vector2> controlPointPosition;
|
||||
|
||||
public PathControlPointPiece(Slider slider, PathControlPoint controlPoint)
|
||||
{
|
||||
@@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
updatePathType();
|
||||
});
|
||||
|
||||
controlPoint.Type.BindValueChanged(_ => updateMarkerDisplay());
|
||||
controlPoint.Changed += updateMarkerDisplay;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
@@ -117,9 +116,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
sliderPosition = slider.PositionBindable.GetBoundCopy();
|
||||
sliderPosition.BindValueChanged(_ => updateMarkerDisplay());
|
||||
|
||||
controlPointPosition = ControlPoint.Position.GetBoundCopy();
|
||||
controlPointPosition.BindValueChanged(_ => updateMarkerDisplay());
|
||||
|
||||
sliderScale = slider.ScaleBindable.GetBoundCopy();
|
||||
sliderScale.BindValueChanged(_ => updateMarkerDisplay());
|
||||
|
||||
@@ -174,8 +170,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
if (e.Button == MouseButton.Left)
|
||||
{
|
||||
dragStartPosition = ControlPoint.Position.Value;
|
||||
dragPathType = PointsInSegment[0].Type.Value;
|
||||
dragStartPosition = ControlPoint.Position;
|
||||
dragPathType = PointsInSegment[0].Type;
|
||||
|
||||
changeHandler?.BeginChange();
|
||||
return true;
|
||||
@@ -186,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
protected override void OnDrag(DragEvent e)
|
||||
{
|
||||
Vector2[] oldControlPoints = slider.Path.ControlPoints.Select(cp => cp.Position.Value).ToArray();
|
||||
Vector2[] oldControlPoints = slider.Path.ControlPoints.Select(cp => cp.Position).ToArray();
|
||||
var oldPosition = slider.Position;
|
||||
var oldStartTime = slider.StartTime;
|
||||
|
||||
@@ -202,15 +198,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
// Since control points are relative to the position of the slider, they all need to be offset backwards by the delta
|
||||
for (int i = 1; i < slider.Path.ControlPoints.Count; i++)
|
||||
slider.Path.ControlPoints[i].Position.Value -= movementDelta;
|
||||
slider.Path.ControlPoints[i].Position -= movementDelta;
|
||||
}
|
||||
else
|
||||
ControlPoint.Position.Value = dragStartPosition + (e.MousePosition - e.MouseDownPosition);
|
||||
ControlPoint.Position = dragStartPosition + (e.MousePosition - e.MouseDownPosition);
|
||||
|
||||
if (!slider.Path.HasValidLength)
|
||||
{
|
||||
for (var i = 0; i < slider.Path.ControlPoints.Count; i++)
|
||||
slider.Path.ControlPoints[i].Position.Value = oldControlPoints[i];
|
||||
slider.Path.ControlPoints[i].Position = oldControlPoints[i];
|
||||
|
||||
slider.Position = oldPosition;
|
||||
slider.StartTime = oldStartTime;
|
||||
@@ -218,7 +214,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
}
|
||||
|
||||
// Maintain the path type in case it got defaulted to bezier at some point during the drag.
|
||||
PointsInSegment[0].Type.Value = dragPathType;
|
||||
PointsInSegment[0].Type = dragPathType;
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e) => changeHandler?.EndChange();
|
||||
@@ -230,19 +226,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
/// </summary>
|
||||
private void updatePathType()
|
||||
{
|
||||
if (ControlPoint.Type.Value != PathType.PerfectCurve)
|
||||
if (ControlPoint.Type != PathType.PerfectCurve)
|
||||
return;
|
||||
|
||||
if (PointsInSegment.Count > 3)
|
||||
ControlPoint.Type.Value = PathType.Bezier;
|
||||
ControlPoint.Type = PathType.Bezier;
|
||||
|
||||
if (PointsInSegment.Count != 3)
|
||||
return;
|
||||
|
||||
ReadOnlySpan<Vector2> points = PointsInSegment.Select(p => p.Position.Value).ToArray();
|
||||
ReadOnlySpan<Vector2> points = PointsInSegment.Select(p => p.Position).ToArray();
|
||||
RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points);
|
||||
if (boundingBox.Width >= 640 || boundingBox.Height >= 480)
|
||||
ControlPoint.Type.Value = PathType.Bezier;
|
||||
ControlPoint.Type = PathType.Bezier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -250,7 +246,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
/// </summary>
|
||||
private void updateMarkerDisplay()
|
||||
{
|
||||
Position = slider.StackedPosition + ControlPoint.Position.Value;
|
||||
Position = slider.StackedPosition + ControlPoint.Position;
|
||||
|
||||
markerRing.Alpha = IsSelected.Value ? 1 : 0;
|
||||
|
||||
@@ -265,7 +261,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
private Color4 getColourFromNodeType()
|
||||
{
|
||||
if (!(ControlPoint.Type.Value is PathType pathType))
|
||||
if (!(ControlPoint.Type is PathType pathType))
|
||||
return colours.Yellow;
|
||||
|
||||
switch (pathType)
|
||||
@@ -284,6 +280,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
}
|
||||
}
|
||||
|
||||
public LocalisableString TooltipText => ControlPoint.Type.Value.ToString() ?? string.Empty;
|
||||
public LocalisableString TooltipText => ControlPoint.Type.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -173,12 +173,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
int thirdPointIndex = indexInSegment + 2;
|
||||
|
||||
if (piece.PointsInSegment.Count > thirdPointIndex + 1)
|
||||
piece.PointsInSegment[thirdPointIndex].Type.Value = piece.PointsInSegment[0].Type.Value;
|
||||
piece.PointsInSegment[thirdPointIndex].Type = piece.PointsInSegment[0].Type;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
piece.ControlPoint.Type.Value = type;
|
||||
piece.ControlPoint.Type = type;
|
||||
}
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
@@ -241,7 +241,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
private MenuItem createMenuItemForPathType(PathType? type)
|
||||
{
|
||||
int totalCount = Pieces.Count(p => p.IsSelected.Value);
|
||||
int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type.Value == type);
|
||||
int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type == type);
|
||||
|
||||
var item = new TernaryStateRadioMenuItem(type == null ? "Inherit" : type.ToString().Humanize(), MenuItemType.Standard, _ =>
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
Debug.Assert(lastPoint != null);
|
||||
|
||||
segmentStart = lastPoint;
|
||||
segmentStart.Type.Value = PathType.Linear;
|
||||
segmentStart.Type = PathType.Linear;
|
||||
|
||||
currentSegmentLength = 1;
|
||||
}
|
||||
@@ -153,15 +153,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
segmentStart.Type.Value = PathType.Linear;
|
||||
segmentStart.Type = PathType.Linear;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
segmentStart.Type.Value = PathType.PerfectCurve;
|
||||
segmentStart.Type = PathType.PerfectCurve;
|
||||
break;
|
||||
|
||||
default:
|
||||
segmentStart.Type.Value = PathType.Bezier;
|
||||
segmentStart.Type = PathType.Bezier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
// The cursor does not overlap a previous control point, so it can be added if not already existing.
|
||||
if (cursor == null)
|
||||
{
|
||||
HitObject.Path.ControlPoints.Add(cursor = new PathControlPoint { Position = { Value = Vector2.Zero } });
|
||||
HitObject.Path.ControlPoints.Add(cursor = new PathControlPoint { Position = Vector2.Zero });
|
||||
|
||||
// The path type should be adjusted in the progression of updatePathType() (Linear -> PC -> Bezier).
|
||||
currentSegmentLength++;
|
||||
@@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
}
|
||||
|
||||
// Update the cursor position.
|
||||
cursor.Position.Value = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position;
|
||||
cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position;
|
||||
}
|
||||
else if (cursor != null)
|
||||
{
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
{
|
||||
Debug.Assert(placementControlPointIndex != null);
|
||||
|
||||
HitObject.Path.ControlPoints[placementControlPointIndex.Value].Position.Value = e.MousePosition - HitObject.Position;
|
||||
HitObject.Path.ControlPoints[placementControlPointIndex.Value].Position = e.MousePosition - HitObject.Position;
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
@@ -182,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
|
||||
for (int i = 0; i < controlPoints.Count - 1; i++)
|
||||
{
|
||||
float dist = new Line(controlPoints[i].Position.Value, controlPoints[i + 1].Position.Value).DistanceToPoint(position);
|
||||
float dist = new Line(controlPoints[i].Position, controlPoints[i + 1].Position).DistanceToPoint(position);
|
||||
|
||||
if (dist < minDistance)
|
||||
{
|
||||
@@ -192,7 +192,7 @@ 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, new PathControlPoint { Position = { Value = position } });
|
||||
controlPoints.Insert(insertionIndex, new PathControlPoint { Position = position });
|
||||
|
||||
return insertionIndex;
|
||||
}
|
||||
@@ -207,8 +207,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
{
|
||||
// The first control point in the slider must have a type, so take it from the previous "first" one
|
||||
// Todo: Should be handled within SliderPath itself
|
||||
if (c == controlPoints[0] && controlPoints.Count > 1 && controlPoints[1].Type.Value == null)
|
||||
controlPoints[1].Type.Value = controlPoints[0].Type.Value;
|
||||
if (c == controlPoints[0] && controlPoints.Count > 1 && controlPoints[1].Type == null)
|
||||
controlPoints[1].Type = controlPoints[0].Type;
|
||||
|
||||
controlPoints.Remove(c);
|
||||
}
|
||||
@@ -222,9 +222,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
|
||||
// The path will have a non-zero offset if the head is removed, but sliders don't support this behaviour since the head is positioned at the slider's position
|
||||
// So the slider needs to be offset by this amount instead, and all control points offset backwards such that the path is re-positioned at (0, 0)
|
||||
Vector2 first = controlPoints[0].Position.Value;
|
||||
Vector2 first = controlPoints[0].Position;
|
||||
foreach (var c in controlPoints)
|
||||
c.Position.Value -= first;
|
||||
c.Position -= first;
|
||||
HitObject.Position += first;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,11 +64,14 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
if (hitObject is DrawableHitCircle circle)
|
||||
{
|
||||
circle.ApproachCircle
|
||||
.FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4)
|
||||
.Expire();
|
||||
using (circle.BeginAbsoluteSequence(circle.HitStateUpdateTime))
|
||||
{
|
||||
circle.ApproachCircle
|
||||
.FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4)
|
||||
.Expire();
|
||||
|
||||
circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
|
||||
circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
if (hitObject is IHasMainCirclePiece mainPieceContainer)
|
||||
|
||||
@@ -98,9 +98,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
foreach (var point in slider.Path.ControlPoints)
|
||||
{
|
||||
point.Position.Value = new Vector2(
|
||||
(direction == Direction.Horizontal ? -1 : 1) * point.Position.Value.X,
|
||||
(direction == Direction.Vertical ? -1 : 1) * point.Position.Value.Y
|
||||
point.Position = new Vector2(
|
||||
(direction == Direction.Horizontal ? -1 : 1) * point.Position.X,
|
||||
(direction == Direction.Vertical ? -1 : 1) * point.Position.Y
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
if (h is IHasPath path)
|
||||
{
|
||||
foreach (var point in path.Path.ControlPoints)
|
||||
point.Position.Value = RotatePointAroundOrigin(point.Position.Value, Vector2.Zero, delta);
|
||||
point.Position = RotatePointAroundOrigin(point.Position, Vector2.Zero, delta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +163,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
private void scaleSlider(Slider slider, Vector2 scale)
|
||||
{
|
||||
referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList();
|
||||
referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type).ToList();
|
||||
|
||||
Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value));
|
||||
Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position));
|
||||
|
||||
// Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0.
|
||||
scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size;
|
||||
@@ -178,13 +178,13 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
foreach (var point in slider.Path.ControlPoints)
|
||||
{
|
||||
oldControlPoints.Enqueue(point.Position.Value);
|
||||
point.Position.Value *= pathRelativeDeltaScale;
|
||||
oldControlPoints.Enqueue(point.Position);
|
||||
point.Position *= pathRelativeDeltaScale;
|
||||
}
|
||||
|
||||
// Maintain the path types in case they were defaulted to bezier at some point during scaling
|
||||
for (int i = 0; i < slider.Path.ControlPoints.Count; ++i)
|
||||
slider.Path.ControlPoints[i].Type.Value = referencePathTypes[i];
|
||||
slider.Path.ControlPoints[i].Type = referencePathTypes[i];
|
||||
|
||||
//if sliderhead or sliderend end up outside playfield, revert scaling.
|
||||
Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider });
|
||||
@@ -194,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
return;
|
||||
|
||||
foreach (var point in slider.Path.ControlPoints)
|
||||
point.Position.Value = oldControlPoints.Dequeue();
|
||||
point.Position = oldControlPoints.Dequeue();
|
||||
}
|
||||
|
||||
private void scaleHitObjects(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Performance;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@@ -20,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
Start = start;
|
||||
LifetimeStart = Start.StartTime;
|
||||
|
||||
bindEvents();
|
||||
}
|
||||
|
||||
private OsuHitObject? end;
|
||||
@@ -41,31 +40,39 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
}
|
||||
}
|
||||
|
||||
private bool wasBound;
|
||||
|
||||
private void bindEvents()
|
||||
{
|
||||
UnbindEvents();
|
||||
|
||||
if (End == null)
|
||||
return;
|
||||
|
||||
// Note: Positions are bound for instantaneous feedback from positional changes from the editor, before ApplyDefaults() is called on hitobjects.
|
||||
Start.DefaultsApplied += onDefaultsApplied;
|
||||
Start.PositionBindable.ValueChanged += onPositionChanged;
|
||||
|
||||
if (End != null)
|
||||
{
|
||||
End.DefaultsApplied += onDefaultsApplied;
|
||||
End.PositionBindable.ValueChanged += onPositionChanged;
|
||||
}
|
||||
End.DefaultsApplied += onDefaultsApplied;
|
||||
End.PositionBindable.ValueChanged += onPositionChanged;
|
||||
|
||||
wasBound = true;
|
||||
}
|
||||
|
||||
public void UnbindEvents()
|
||||
{
|
||||
if (!wasBound)
|
||||
return;
|
||||
|
||||
Debug.Assert(End != null);
|
||||
|
||||
Start.DefaultsApplied -= onDefaultsApplied;
|
||||
Start.PositionBindable.ValueChanged -= onPositionChanged;
|
||||
|
||||
if (End != null)
|
||||
{
|
||||
End.DefaultsApplied -= onDefaultsApplied;
|
||||
End.PositionBindable.ValueChanged -= onPositionChanged;
|
||||
}
|
||||
End.DefaultsApplied -= onDefaultsApplied;
|
||||
End.PositionBindable.ValueChanged -= onPositionChanged;
|
||||
|
||||
wasBound = false;
|
||||
}
|
||||
|
||||
private void onDefaultsApplied(HitObject obj) => refreshLifetimes();
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
base.PlayAnimation();
|
||||
|
||||
if (Result != HitResult.Miss)
|
||||
JudgementText.TransformSpacingTo(Vector2.Zero).Then().TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint);
|
||||
JudgementText.ScaleTo(new Vector2(0.8f, 1)).Then().ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position.Value, c.Type.Value)));
|
||||
path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position, c.Type)));
|
||||
path.ExpectedDistance.Value = value.ExpectedDistance.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||
protected override bool InterpolateMovements => !disjointTrail;
|
||||
|
||||
protected override float IntervalMultiplier => 1 / Math.Max(cursorSize.Value, 1);
|
||||
protected override bool AvoidDrawingNearCursor => !disjointTrail;
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
|
||||
@@ -138,6 +138,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
protected virtual bool InterpolateMovements => true;
|
||||
|
||||
protected virtual float IntervalMultiplier => 1.0f;
|
||||
protected virtual bool AvoidDrawingNearCursor => false;
|
||||
|
||||
private Vector2? lastPosition;
|
||||
private readonly InputResampler resampler = new InputResampler();
|
||||
@@ -171,8 +172,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
Vector2 direction = diff / distance;
|
||||
|
||||
float interval = partSize.X / 2.5f * IntervalMultiplier;
|
||||
float stopAt = distance - (AvoidDrawingNearCursor ? interval : 0);
|
||||
|
||||
for (float d = interval; d < distance; d += interval)
|
||||
for (float d = interval; d < stopAt; d += interval)
|
||||
{
|
||||
lastPosition = pos1 + direction * d;
|
||||
addPart(lastPosition.Value);
|
||||
|
||||
@@ -119,9 +119,9 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y));
|
||||
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray();
|
||||
foreach (var point in controlPoints)
|
||||
point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y);
|
||||
point.Position = new Vector2(-point.Position.X, point.Position.Y);
|
||||
|
||||
slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value);
|
||||
}
|
||||
@@ -140,9 +140,9 @@ namespace osu.Game.Rulesets.Osu.Utils
|
||||
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
|
||||
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray();
|
||||
var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray();
|
||||
foreach (var point in controlPoints)
|
||||
point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y);
|
||||
point.Position = new Vector2(point.Position.X, -point.Position.Y);
|
||||
|
||||
slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
|
||||
/// <summary>
|
||||
/// Calculates the colour coefficient of taiko difficulty.
|
||||
/// </summary>
|
||||
public class Colour : StrainSkill
|
||||
public class Colour : StrainDecaySkill
|
||||
{
|
||||
protected override double SkillMultiplier => 1;
|
||||
protected override double StrainDecayBase => 0.4;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
|
||||
/// <summary>
|
||||
/// Calculates the rhythm coefficient of taiko difficulty.
|
||||
/// </summary>
|
||||
public class Rhythm : StrainSkill
|
||||
public class Rhythm : StrainDecaySkill
|
||||
{
|
||||
protected override double SkillMultiplier => 10;
|
||||
protected override double StrainDecayBase => 0;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills
|
||||
/// <remarks>
|
||||
/// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit).
|
||||
/// </remarks>
|
||||
public class Stamina : StrainSkill
|
||||
public class Stamina : StrainDecaySkill
|
||||
{
|
||||
protected override double SkillMultiplier => 1;
|
||||
protected override double StrainDecayBase => 0.4;
|
||||
|
||||
@@ -1,56 +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 NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
[TestFixture]
|
||||
public class BeatmapDifficultyCacheTest
|
||||
{
|
||||
[Test]
|
||||
public void TestKeyEqualsWithDifferentModInstances()
|
||||
{
|
||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||
|
||||
Assert.That(key1, Is.EqualTo(key2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKeyEqualsWithDifferentModOrder()
|
||||
{
|
||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
||||
|
||||
Assert.That(key1, Is.EqualTo(key2));
|
||||
}
|
||||
|
||||
[TestCase(1.3, DifficultyRating.Easy)]
|
||||
[TestCase(1.993, DifficultyRating.Easy)]
|
||||
[TestCase(1.998, DifficultyRating.Normal)]
|
||||
[TestCase(2.4, DifficultyRating.Normal)]
|
||||
[TestCase(2.693, DifficultyRating.Normal)]
|
||||
[TestCase(2.698, DifficultyRating.Hard)]
|
||||
[TestCase(3.5, DifficultyRating.Hard)]
|
||||
[TestCase(3.993, DifficultyRating.Hard)]
|
||||
[TestCase(3.997, DifficultyRating.Insane)]
|
||||
[TestCase(5.0, DifficultyRating.Insane)]
|
||||
[TestCase(5.292, DifficultyRating.Insane)]
|
||||
[TestCase(5.297, DifficultyRating.Expert)]
|
||||
[TestCase(6.2, DifficultyRating.Expert)]
|
||||
[TestCase(6.493, DifficultyRating.Expert)]
|
||||
[TestCase(6.498, DifficultyRating.ExpertPlus)]
|
||||
[TestCase(8.3, DifficultyRating.ExpertPlus)]
|
||||
public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket)
|
||||
{
|
||||
var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating);
|
||||
|
||||
Assert.AreEqual(expectedBracket, actualBracket);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,12 +58,13 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", metadata.AudioFile);
|
||||
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
||||
Assert.AreEqual(164471, metadata.PreviewTime);
|
||||
Assert.IsFalse(beatmapInfo.Countdown);
|
||||
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
||||
Assert.IsTrue(beatmapInfo.RulesetID == 0);
|
||||
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
||||
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
||||
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
||||
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
||||
Assert.AreEqual(0, beatmapInfo.CountdownOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,111 +666,111 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
// Multi-segment
|
||||
var first = ((IHasPath)decoded.HitObjects[0]).Path;
|
||||
|
||||
Assert.That(first.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(first.ControlPoints[0].Type.Value, Is.EqualTo(PathType.PerfectCurve));
|
||||
Assert.That(first.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(161, -244)));
|
||||
Assert.That(first.ControlPoints[1].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(first.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(first.ControlPoints[0].Type, Is.EqualTo(PathType.PerfectCurve));
|
||||
Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244)));
|
||||
Assert.That(first.ControlPoints[1].Type, Is.EqualTo(null));
|
||||
|
||||
Assert.That(first.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(376, -3)));
|
||||
Assert.That(first.ControlPoints[2].Type.Value, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(first.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(68, 15)));
|
||||
Assert.That(first.ControlPoints[3].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(first.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(259, -132)));
|
||||
Assert.That(first.ControlPoints[4].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(first.ControlPoints[5].Position.Value, Is.EqualTo(new Vector2(92, -107)));
|
||||
Assert.That(first.ControlPoints[5].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3)));
|
||||
Assert.That(first.ControlPoints[2].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15)));
|
||||
Assert.That(first.ControlPoints[3].Type, Is.EqualTo(null));
|
||||
Assert.That(first.ControlPoints[4].Position, Is.EqualTo(new Vector2(259, -132)));
|
||||
Assert.That(first.ControlPoints[4].Type, Is.EqualTo(null));
|
||||
Assert.That(first.ControlPoints[5].Position, Is.EqualTo(new Vector2(92, -107)));
|
||||
Assert.That(first.ControlPoints[5].Type, Is.EqualTo(null));
|
||||
|
||||
// Single-segment
|
||||
var second = ((IHasPath)decoded.HitObjects[1]).Path;
|
||||
|
||||
Assert.That(second.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(second.ControlPoints[0].Type.Value, Is.EqualTo(PathType.PerfectCurve));
|
||||
Assert.That(second.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(161, -244)));
|
||||
Assert.That(second.ControlPoints[1].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(second.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(376, -3)));
|
||||
Assert.That(second.ControlPoints[2].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(second.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(second.ControlPoints[0].Type, Is.EqualTo(PathType.PerfectCurve));
|
||||
Assert.That(second.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244)));
|
||||
Assert.That(second.ControlPoints[1].Type, Is.EqualTo(null));
|
||||
Assert.That(second.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3)));
|
||||
Assert.That(second.ControlPoints[2].Type, Is.EqualTo(null));
|
||||
|
||||
// Implicit multi-segment
|
||||
var third = ((IHasPath)decoded.HitObjects[2]).Path;
|
||||
|
||||
Assert.That(third.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(third.ControlPoints[0].Type.Value, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(third.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(0, 192)));
|
||||
Assert.That(third.ControlPoints[1].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(224, 192)));
|
||||
Assert.That(third.ControlPoints[2].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(third.ControlPoints[0].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(third.ControlPoints[1].Position, Is.EqualTo(new Vector2(0, 192)));
|
||||
Assert.That(third.ControlPoints[1].Type, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[2].Position, Is.EqualTo(new Vector2(224, 192)));
|
||||
Assert.That(third.ControlPoints[2].Type, Is.EqualTo(null));
|
||||
|
||||
Assert.That(third.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(224, 0)));
|
||||
Assert.That(third.ControlPoints[3].Type.Value, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(third.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(224, -192)));
|
||||
Assert.That(third.ControlPoints[4].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[5].Position.Value, Is.EqualTo(new Vector2(480, -192)));
|
||||
Assert.That(third.ControlPoints[5].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[6].Position.Value, Is.EqualTo(new Vector2(480, 0)));
|
||||
Assert.That(third.ControlPoints[6].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[3].Position, Is.EqualTo(new Vector2(224, 0)));
|
||||
Assert.That(third.ControlPoints[3].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(third.ControlPoints[4].Position, Is.EqualTo(new Vector2(224, -192)));
|
||||
Assert.That(third.ControlPoints[4].Type, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[5].Position, Is.EqualTo(new Vector2(480, -192)));
|
||||
Assert.That(third.ControlPoints[5].Type, Is.EqualTo(null));
|
||||
Assert.That(third.ControlPoints[6].Position, Is.EqualTo(new Vector2(480, 0)));
|
||||
Assert.That(third.ControlPoints[6].Type, Is.EqualTo(null));
|
||||
|
||||
// Last control point duplicated
|
||||
var fourth = ((IHasPath)decoded.HitObjects[3]).Path;
|
||||
|
||||
Assert.That(fourth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(fourth.ControlPoints[0].Type.Value, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(fourth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(1, 1)));
|
||||
Assert.That(fourth.ControlPoints[1].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(2, 2)));
|
||||
Assert.That(fourth.ControlPoints[2].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fourth.ControlPoints[3].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fourth.ControlPoints[4].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(fourth.ControlPoints[0].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(fourth.ControlPoints[1].Position, Is.EqualTo(new Vector2(1, 1)));
|
||||
Assert.That(fourth.ControlPoints[1].Type, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[2].Position, Is.EqualTo(new Vector2(2, 2)));
|
||||
Assert.That(fourth.ControlPoints[2].Type, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[3].Position, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fourth.ControlPoints[3].Type, Is.EqualTo(null));
|
||||
Assert.That(fourth.ControlPoints[4].Position, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fourth.ControlPoints[4].Type, Is.EqualTo(null));
|
||||
|
||||
// Last control point in segment duplicated
|
||||
var fifth = ((IHasPath)decoded.HitObjects[4]).Path;
|
||||
|
||||
Assert.That(fifth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(fifth.ControlPoints[0].Type.Value, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(fifth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(1, 1)));
|
||||
Assert.That(fifth.ControlPoints[1].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(2, 2)));
|
||||
Assert.That(fifth.ControlPoints[2].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fifth.ControlPoints[3].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fifth.ControlPoints[4].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(fifth.ControlPoints[0].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(fifth.ControlPoints[1].Position, Is.EqualTo(new Vector2(1, 1)));
|
||||
Assert.That(fifth.ControlPoints[1].Type, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[2].Position, Is.EqualTo(new Vector2(2, 2)));
|
||||
Assert.That(fifth.ControlPoints[2].Type, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[3].Position, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fifth.ControlPoints[3].Type, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[4].Position, Is.EqualTo(new Vector2(3, 3)));
|
||||
Assert.That(fifth.ControlPoints[4].Type, Is.EqualTo(null));
|
||||
|
||||
Assert.That(fifth.ControlPoints[5].Position.Value, Is.EqualTo(new Vector2(4, 4)));
|
||||
Assert.That(fifth.ControlPoints[5].Type.Value, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(fifth.ControlPoints[6].Position.Value, Is.EqualTo(new Vector2(5, 5)));
|
||||
Assert.That(fifth.ControlPoints[6].Type.Value, Is.EqualTo(null));
|
||||
Assert.That(fifth.ControlPoints[5].Position, Is.EqualTo(new Vector2(4, 4)));
|
||||
Assert.That(fifth.ControlPoints[5].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(fifth.ControlPoints[6].Position, Is.EqualTo(new Vector2(5, 5)));
|
||||
Assert.That(fifth.ControlPoints[6].Type, Is.EqualTo(null));
|
||||
|
||||
// Implicit perfect-curve multi-segment(Should convert to bezier to match stable)
|
||||
var sixth = ((IHasPath)decoded.HitObjects[5]).Path;
|
||||
|
||||
Assert.That(sixth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(sixth.ControlPoints[0].Type.Value == PathType.Bezier);
|
||||
Assert.That(sixth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145)));
|
||||
Assert.That(sixth.ControlPoints[1].Type.Value == null);
|
||||
Assert.That(sixth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75)));
|
||||
Assert.That(sixth.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(sixth.ControlPoints[0].Type == PathType.Bezier);
|
||||
Assert.That(sixth.ControlPoints[1].Position, Is.EqualTo(new Vector2(75, 145)));
|
||||
Assert.That(sixth.ControlPoints[1].Type == null);
|
||||
Assert.That(sixth.ControlPoints[2].Position, Is.EqualTo(new Vector2(170, 75)));
|
||||
|
||||
Assert.That(sixth.ControlPoints[2].Type.Value == PathType.Bezier);
|
||||
Assert.That(sixth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145)));
|
||||
Assert.That(sixth.ControlPoints[3].Type.Value == null);
|
||||
Assert.That(sixth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20)));
|
||||
Assert.That(sixth.ControlPoints[4].Type.Value == null);
|
||||
Assert.That(sixth.ControlPoints[2].Type == PathType.Bezier);
|
||||
Assert.That(sixth.ControlPoints[3].Position, Is.EqualTo(new Vector2(300, 145)));
|
||||
Assert.That(sixth.ControlPoints[3].Type == null);
|
||||
Assert.That(sixth.ControlPoints[4].Position, Is.EqualTo(new Vector2(410, 20)));
|
||||
Assert.That(sixth.ControlPoints[4].Type == null);
|
||||
|
||||
// Explicit perfect-curve multi-segment(Should not convert to bezier)
|
||||
var seventh = ((IHasPath)decoded.HitObjects[6]).Path;
|
||||
|
||||
Assert.That(seventh.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(seventh.ControlPoints[0].Type.Value == PathType.PerfectCurve);
|
||||
Assert.That(seventh.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145)));
|
||||
Assert.That(seventh.ControlPoints[1].Type.Value == null);
|
||||
Assert.That(seventh.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75)));
|
||||
Assert.That(seventh.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero));
|
||||
Assert.That(seventh.ControlPoints[0].Type == PathType.PerfectCurve);
|
||||
Assert.That(seventh.ControlPoints[1].Position, Is.EqualTo(new Vector2(75, 145)));
|
||||
Assert.That(seventh.ControlPoints[1].Type == null);
|
||||
Assert.That(seventh.ControlPoints[2].Position, Is.EqualTo(new Vector2(170, 75)));
|
||||
|
||||
Assert.That(seventh.ControlPoints[2].Type.Value == PathType.PerfectCurve);
|
||||
Assert.That(seventh.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145)));
|
||||
Assert.That(seventh.ControlPoints[3].Type.Value == null);
|
||||
Assert.That(seventh.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20)));
|
||||
Assert.That(seventh.ControlPoints[4].Type.Value == null);
|
||||
Assert.That(seventh.ControlPoints[2].Type == PathType.PerfectCurve);
|
||||
Assert.That(seventh.ControlPoints[3].Position, Is.EqualTo(new Vector2(300, 145)));
|
||||
Assert.That(seventh.ControlPoints[3].Type == null);
|
||||
Assert.That(seventh.ControlPoints[4].Position, Is.EqualTo(new Vector2(410, 20)));
|
||||
Assert.That(seventh.ControlPoints[4].Type == null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
|
||||
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||
|
||||
protected override ISkin GetSkin() => throw new NotImplementedException();
|
||||
protected internal override ISkin GetSkin() => throw new NotImplementedException();
|
||||
|
||||
public override Stream GetStream(string storagePath) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -50,12 +50,13 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
var beatmap = decodeAsJson(normal);
|
||||
var beatmapInfo = beatmap.BeatmapInfo;
|
||||
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
|
||||
Assert.AreEqual(false, beatmapInfo.Countdown);
|
||||
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
|
||||
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
|
||||
Assert.IsTrue(beatmapInfo.RulesetID == 0);
|
||||
Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks);
|
||||
Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard);
|
||||
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
||||
Assert.AreEqual(0, beatmapInfo.CountdownOffset);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
// 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.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.Beatmaps
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneBeatmapDifficultyCache : OsuTestScene
|
||||
{
|
||||
public const double BASE_STARS = 5.55;
|
||||
|
||||
private BeatmapSetInfo importedSet;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
|
||||
private TestBeatmapDifficultyCache difficultyCache;
|
||||
|
||||
private IBindable<StarDifficulty?> starDifficultyBindable;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase osu)
|
||||
{
|
||||
importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).Result;
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("setup difficulty cache", () =>
|
||||
{
|
||||
SelectedMods.Value = Array.Empty<Mod>();
|
||||
|
||||
Child = difficultyCache = new TestBeatmapDifficultyCache();
|
||||
|
||||
starDifficultyBindable = difficultyCache.GetBindableDifficulty(importedSet.Beatmaps.First());
|
||||
});
|
||||
|
||||
AddUntilStep($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStarDifficultyChangesOnModSettings()
|
||||
{
|
||||
OsuModDoubleTime dt = null;
|
||||
|
||||
AddStep("set computation function", () => difficultyCache.ComputeDifficulty = lookup =>
|
||||
{
|
||||
var modRateAdjust = (ModRateAdjust)lookup.OrderedMods.SingleOrDefault(mod => mod is ModRateAdjust);
|
||||
return new StarDifficulty(BASE_STARS + modRateAdjust?.SpeedChange.Value ?? 0, 0);
|
||||
});
|
||||
|
||||
AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } });
|
||||
AddUntilStep($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.5);
|
||||
|
||||
AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 1.25);
|
||||
AddUntilStep($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.25);
|
||||
|
||||
AddStep("change selected mod to NC", () => SelectedMods.Value = new[] { new OsuModNightcore { SpeedChange = { Value = 1.75 } } });
|
||||
AddUntilStep($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.75);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStarDifficultyAdjustHashCodeConflict()
|
||||
{
|
||||
OsuModDifficultyAdjust difficultyAdjust = null;
|
||||
|
||||
AddStep("set computation function", () => difficultyCache.ComputeDifficulty = lookup =>
|
||||
{
|
||||
var modDifficultyAdjust = (ModDifficultyAdjust)lookup.OrderedMods.SingleOrDefault(mod => mod is ModDifficultyAdjust);
|
||||
return new StarDifficulty(BASE_STARS * (modDifficultyAdjust?.OverallDifficulty.Value ?? 1), 0);
|
||||
});
|
||||
|
||||
AddStep("change selected mod to DA", () => SelectedMods.Value = new[] { difficultyAdjust = new OsuModDifficultyAdjust() });
|
||||
AddUntilStep($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS);
|
||||
|
||||
AddStep("change DA difficulty to 0.5", () => difficultyAdjust.OverallDifficulty.Value = 0.5f);
|
||||
AddUntilStep($"star difficulty -> {BASE_STARS * 0.5f}", () => starDifficultyBindable.Value?.Stars == BASE_STARS / 2);
|
||||
|
||||
// hash code of 0 (the value) conflicts with the hash code of null (the initial/default value).
|
||||
// it's important that the mod reference and its underlying bindable references stay the same to demonstrate this failure.
|
||||
AddStep("change DA difficulty to 0", () => difficultyAdjust.OverallDifficulty.Value = 0);
|
||||
AddUntilStep("star difficulty -> 0", () => starDifficultyBindable.Value?.Stars == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKeyEqualsWithDifferentModInstances()
|
||||
{
|
||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||
|
||||
Assert.That(key1, Is.EqualTo(key2));
|
||||
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKeyEqualsWithDifferentModOrder()
|
||||
{
|
||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
|
||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
|
||||
|
||||
Assert.That(key1, Is.EqualTo(key2));
|
||||
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKeyDoesntEqualWithDifferentModSettings()
|
||||
{
|
||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
|
||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
|
||||
|
||||
Assert.That(key1, Is.Not.EqualTo(key2));
|
||||
Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestKeyEqualWithMatchingModSettings()
|
||||
{
|
||||
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||
|
||||
Assert.That(key1, Is.EqualTo(key2));
|
||||
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
|
||||
}
|
||||
|
||||
[TestCase(1.3, DifficultyRating.Easy)]
|
||||
[TestCase(1.993, DifficultyRating.Easy)]
|
||||
[TestCase(1.998, DifficultyRating.Normal)]
|
||||
[TestCase(2.4, DifficultyRating.Normal)]
|
||||
[TestCase(2.693, DifficultyRating.Normal)]
|
||||
[TestCase(2.698, DifficultyRating.Hard)]
|
||||
[TestCase(3.5, DifficultyRating.Hard)]
|
||||
[TestCase(3.993, DifficultyRating.Hard)]
|
||||
[TestCase(3.997, DifficultyRating.Insane)]
|
||||
[TestCase(5.0, DifficultyRating.Insane)]
|
||||
[TestCase(5.292, DifficultyRating.Insane)]
|
||||
[TestCase(5.297, DifficultyRating.Expert)]
|
||||
[TestCase(6.2, DifficultyRating.Expert)]
|
||||
[TestCase(6.493, DifficultyRating.Expert)]
|
||||
[TestCase(6.498, DifficultyRating.ExpertPlus)]
|
||||
[TestCase(8.3, DifficultyRating.ExpertPlus)]
|
||||
public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket)
|
||||
{
|
||||
var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating);
|
||||
|
||||
Assert.AreEqual(expectedBracket, actualBracket);
|
||||
}
|
||||
|
||||
private class TestBeatmapDifficultyCache : BeatmapDifficultyCache
|
||||
{
|
||||
public Func<DifficultyCacheLookup, StarDifficulty> ComputeDifficulty { get; set; }
|
||||
|
||||
protected override Task<StarDifficulty> ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken token = default)
|
||||
{
|
||||
return Task.FromResult(ComputeDifficulty?.Invoke(lookup) ?? new StarDifficulty(BASE_STARS, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -19,6 +20,7 @@ namespace osu.Game.Tests.Chat
|
||||
{
|
||||
private ChannelManager channelManager;
|
||||
private int currentMessageId;
|
||||
private List<Message> sentMessages;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
@@ -34,6 +36,7 @@ namespace osu.Game.Tests.Chat
|
||||
AddStep("register request handling", () =>
|
||||
{
|
||||
currentMessageId = 0;
|
||||
sentMessages = new List<Message>();
|
||||
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
@@ -44,16 +47,11 @@ namespace osu.Game.Tests.Chat
|
||||
return true;
|
||||
|
||||
case PostMessageRequest postMessage:
|
||||
postMessage.TriggerSuccess(new Message(++currentMessageId)
|
||||
{
|
||||
IsAction = postMessage.Message.IsAction,
|
||||
ChannelId = postMessage.Message.ChannelId,
|
||||
Content = postMessage.Message.Content,
|
||||
Links = postMessage.Message.Links,
|
||||
Timestamp = postMessage.Message.Timestamp,
|
||||
Sender = postMessage.Message.Sender
|
||||
});
|
||||
handlePostMessageRequest(postMessage);
|
||||
return true;
|
||||
|
||||
case MarkChannelAsReadRequest markRead:
|
||||
handleMarkChannelAsReadRequest(markRead);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -83,12 +81,65 @@ namespace osu.Game.Tests.Chat
|
||||
AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMarkAsReadIgnoringLocalMessages()
|
||||
{
|
||||
Channel channel = null;
|
||||
|
||||
AddStep("join channel and select it", () =>
|
||||
{
|
||||
channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public));
|
||||
channelManager.CurrentChannel.Value = channel;
|
||||
});
|
||||
|
||||
AddStep("post message", () => channelManager.PostMessage("Something interesting"));
|
||||
|
||||
AddStep("post /help command", () => channelManager.PostCommand("help", channel));
|
||||
AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel));
|
||||
AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel));
|
||||
AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel));
|
||||
AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel));
|
||||
|
||||
AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel));
|
||||
AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id);
|
||||
}
|
||||
|
||||
private void handlePostMessageRequest(PostMessageRequest request)
|
||||
{
|
||||
var message = new Message(++currentMessageId)
|
||||
{
|
||||
IsAction = request.Message.IsAction,
|
||||
ChannelId = request.Message.ChannelId,
|
||||
Content = request.Message.Content,
|
||||
Links = request.Message.Links,
|
||||
Timestamp = request.Message.Timestamp,
|
||||
Sender = request.Message.Sender
|
||||
};
|
||||
|
||||
sentMessages.Add(message);
|
||||
request.TriggerSuccess(message);
|
||||
}
|
||||
|
||||
private void handleMarkChannelAsReadRequest(MarkChannelAsReadRequest request)
|
||||
{
|
||||
// only accept messages that were sent through the API
|
||||
if (sentMessages.Contains(request.Message))
|
||||
{
|
||||
request.TriggerSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
request.TriggerFailure(new APIException("unknown message!", null));
|
||||
}
|
||||
}
|
||||
|
||||
private Channel createChannel(int id, ChannelType type) => new Channel(new User())
|
||||
{
|
||||
Id = id,
|
||||
Name = $"Channel {id}",
|
||||
Topic = $"Topic of channel {id} with type {type}",
|
||||
Type = type,
|
||||
LastMessageId = 0,
|
||||
};
|
||||
|
||||
private class ChannelManagerContainer : CompositeDrawable
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Collections.IO
|
||||
@@ -127,7 +128,7 @@ namespace osu.Game.Tests.Collections.IO
|
||||
[Test]
|
||||
public async Task TestSaveAndReload()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost())
|
||||
using (HeadlessGameHost host = new TestRunHeadlessGameHost("TestSaveAndReload", bypassCleanup: true))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -148,7 +149,7 @@ namespace osu.Game.Tests.Collections.IO
|
||||
}
|
||||
}
|
||||
|
||||
using (HeadlessGameHost host = new HeadlessGameHost("TestSaveAndReload"))
|
||||
using (HeadlessGameHost host = new TestRunHeadlessGameHost("TestSaveAndReload"))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin() => new TestSkin("test-sample", resources);
|
||||
protected internal override ISkin GetSkin() => new TestSkin("test-sample", resources);
|
||||
}
|
||||
|
||||
private class TestDrawableStoryboardSample : DrawableStoryboardSample
|
||||
|
||||
@@ -8,7 +8,7 @@ using osu.Framework.Input;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Input;
|
||||
using osu.Game.Tests.Visual.Navigation;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
||||
namespace osu.Game.Tests.Input
|
||||
{
|
||||
|
||||
@@ -6,10 +6,10 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.IO;
|
||||
|
||||
@@ -278,7 +278,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
|
||||
private static string getDefaultLocationFor(string testTypeName)
|
||||
{
|
||||
string path = Path.Combine(RuntimeInfo.StartupDirectory, "headless", testTypeName);
|
||||
string path = Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, testTypeName);
|
||||
|
||||
if (Directory.Exists(path))
|
||||
Directory.Delete(path, true);
|
||||
@@ -288,7 +288,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
|
||||
private string prepareCustomPath(string suffix = "")
|
||||
{
|
||||
string path = Path.Combine(RuntimeInfo.StartupDirectory, $"custom-path{suffix}");
|
||||
string path = Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, $"custom-path{suffix}");
|
||||
|
||||
if (Directory.Exists(path))
|
||||
Directory.Delete(path, true);
|
||||
@@ -308,6 +308,19 @@ namespace osu.Game.Tests.NonVisual
|
||||
InitialStorage = new DesktopStorage(defaultStorageLocation, this);
|
||||
InitialStorage.DeleteDirectory(string.Empty);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
try
|
||||
{
|
||||
// the storage may have changed from the initial location.
|
||||
// this handles cleanup of the initial location.
|
||||
InitialStorage.DeleteDirectory(string.Empty);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// 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 MessagePack;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
|
||||
namespace osu.Game.Tests.Online
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestMultiplayerMessagePackSerialization
|
||||
{
|
||||
[Test]
|
||||
public void TestSerialiseRoom()
|
||||
{
|
||||
var room = new MultiplayerRoom(1)
|
||||
{
|
||||
MatchState = new TeamVersusRoomState()
|
||||
};
|
||||
|
||||
var serialized = MessagePackSerializer.Serialize(room);
|
||||
|
||||
var deserialized = MessagePackSerializer.Deserialize<MultiplayerRoom>(serialized);
|
||||
|
||||
Assert.IsTrue(deserialized.MatchState is TeamVersusRoomState);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSerialiseUserStateExpected()
|
||||
{
|
||||
var state = new TeamVersusUserState();
|
||||
|
||||
var serialized = MessagePackSerializer.Serialize(typeof(MatchUserState), state);
|
||||
var deserialized = MessagePackSerializer.Deserialize<MatchUserState>(serialized);
|
||||
|
||||
Assert.IsTrue(deserialized is TeamVersusUserState);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSerialiseUnionFailsWithSingalR()
|
||||
{
|
||||
var state = new TeamVersusUserState();
|
||||
|
||||
// SignalR serialises using the actual type, rather than a base specification.
|
||||
var serialized = MessagePackSerializer.Serialize(typeof(TeamVersusUserState), state);
|
||||
|
||||
// works with explicit type specified.
|
||||
MessagePackSerializer.Deserialize<TeamVersusUserState>(serialized);
|
||||
|
||||
// fails with base (union) type.
|
||||
Assert.Throws<MessagePackSerializationException>(() => MessagePackSerializer.Deserialize<MatchUserState>(serialized));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSerialiseUnionSucceedsWithWorkaround()
|
||||
{
|
||||
var state = new TeamVersusUserState();
|
||||
|
||||
// SignalR serialises using the actual type, rather than a base specification.
|
||||
var serialized = MessagePackSerializer.Serialize(typeof(TeamVersusUserState), state, SignalRUnionWorkaroundResolver.OPTIONS);
|
||||
|
||||
// works with explicit type specified.
|
||||
MessagePackSerializer.Deserialize<TeamVersusUserState>(serialized);
|
||||
|
||||
// works with custom resolver.
|
||||
var deserialized = MessagePackSerializer.Deserialize<MatchUserState>(serialized, SignalRUnionWorkaroundResolver.OPTIONS);
|
||||
Assert.IsTrue(deserialized is TeamVersusUserState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ namespace osu.Game.Tests.Resources
|
||||
{
|
||||
public static class TestResources
|
||||
{
|
||||
public const double QUICK_BEATMAP_LENGTH = 10000;
|
||||
|
||||
public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly);
|
||||
|
||||
public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}");
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
osu file format v14
|
||||
|
||||
[General]
|
||||
Countdown: 2
|
||||
CountdownOffset: 3
|
||||
@@ -50,10 +50,10 @@ namespace osu.Game.Tests.Skins.IO
|
||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin2.osk"));
|
||||
|
||||
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(1));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Count, Is.EqualTo(1));
|
||||
|
||||
// the first should be overwritten by the second import.
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -76,10 +76,10 @@ namespace osu.Game.Tests.Skins.IO
|
||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk"));
|
||||
|
||||
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(2));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Count, Is.EqualTo(2));
|
||||
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -101,10 +101,10 @@ namespace osu.Game.Tests.Skins.IO
|
||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2.1", "skinner"), "skin2.osk"));
|
||||
|
||||
Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Count, Is.EqualTo(2));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Count, Is.EqualTo(2));
|
||||
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID));
|
||||
Assert.That(osu.Dependencies.Get<SkinManager>().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -138,16 +138,42 @@ namespace osu.Game.Tests.Skins.IO
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryStream createOsk(string name, string author)
|
||||
[Test]
|
||||
public async Task TestSameMetadataNameDifferentFolderName()
|
||||
{
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = LoadOsuIntoHost(host);
|
||||
|
||||
var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1", false), "my custom skin 1"));
|
||||
Assert.That(imported.Name, Is.EqualTo("name 1 [my custom skin 1]"));
|
||||
Assert.That(imported.Creator, Is.EqualTo("author 1"));
|
||||
|
||||
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1", false), "my custom skin 2"));
|
||||
Assert.That(imported2.Name, Is.EqualTo("name 1 [my custom skin 2]"));
|
||||
Assert.That(imported2.Creator, Is.EqualTo("author 1"));
|
||||
|
||||
Assert.That(imported2.Hash, Is.Not.EqualTo(imported.Hash));
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryStream createOsk(string name, string author, bool makeUnique = true)
|
||||
{
|
||||
var zipStream = new MemoryStream();
|
||||
using var zip = ZipArchive.Create();
|
||||
zip.AddEntry("skin.ini", generateSkinIni(name, author));
|
||||
zip.AddEntry("skin.ini", generateSkinIni(name, author, makeUnique));
|
||||
zip.SaveTo(zipStream);
|
||||
return zipStream;
|
||||
}
|
||||
|
||||
private MemoryStream generateSkinIni(string name, string author)
|
||||
private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
@@ -155,8 +181,12 @@ namespace osu.Game.Tests.Skins.IO
|
||||
writer.WriteLine("[General]");
|
||||
writer.WriteLine($"Name: {name}");
|
||||
writer.WriteLine($"Author: {author}");
|
||||
writer.WriteLine();
|
||||
writer.WriteLine($"# unique {Guid.NewGuid()}");
|
||||
|
||||
if (makeUnique)
|
||||
{
|
||||
writer.WriteLine();
|
||||
writer.WriteLine($"# unique {Guid.NewGuid()}");
|
||||
}
|
||||
|
||||
writer.Flush();
|
||||
|
||||
|
||||
@@ -133,11 +133,12 @@ namespace osu.Game.Tests.Skins
|
||||
[Test]
|
||||
public void TestEmptyComboColoursNoFallback()
|
||||
{
|
||||
AddStep("Add custom combo colours to user skin", () => userSource.Configuration.AddComboColours(
|
||||
AddStep("Add custom combo colours to user skin", () => userSource.Configuration.CustomComboColours = new List<Color4>
|
||||
{
|
||||
new Color4(100, 150, 200, 255),
|
||||
new Color4(55, 110, 166, 255),
|
||||
new Color4(75, 125, 175, 255)
|
||||
));
|
||||
});
|
||||
|
||||
AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false);
|
||||
|
||||
|
||||
@@ -78,6 +78,24 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClampWhenSeekOutsideBeatmapBounds()
|
||||
{
|
||||
AddStep("stop clock", Clock.Stop);
|
||||
|
||||
AddStep("seek before start time", () => Clock.Seek(-1000));
|
||||
AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0);
|
||||
|
||||
AddStep("seek beyond track length", () => Clock.Seek(Clock.TrackLength + 1000));
|
||||
AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
|
||||
AddStep("seek smoothly before start time", () => Clock.SeekSmoothlyTo(-1000));
|
||||
AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0);
|
||||
|
||||
AddStep("seek smoothly beyond track length", () => Clock.SeekSmoothlyTo(Clock.TrackLength + 1000));
|
||||
AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
Beatmap.Disabled = false;
|
||||
|
||||
@@ -0,0 +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.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osu.Game.Screens.Edit.Components.Menus;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
public class TestSceneEditorScreenModes : EditorTestScene
|
||||
{
|
||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||
|
||||
[Test]
|
||||
public void TestSwitchScreensInstantaneously()
|
||||
{
|
||||
AddStep("switch between all screens at once", () =>
|
||||
{
|
||||
foreach (var screen in Enum.GetValues(typeof(EditorScreenMode)).Cast<EditorScreenMode>())
|
||||
Editor.ChildrenOfType<EditorMenuBar>().Single().Mode.Value = screen;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
this.beatmapSkin = beatmapSkin;
|
||||
}
|
||||
|
||||
protected override ISkin GetSkin() => beatmapSkin;
|
||||
protected internal override ISkin GetSkin() => beatmapSkin;
|
||||
}
|
||||
|
||||
private class TestOsuRuleset : OsuRuleset
|
||||
|
||||
@@ -12,12 +12,15 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
|
||||
{
|
||||
private OsuConfigManager localConfig;
|
||||
|
||||
private HUDOverlay hudOverlay;
|
||||
|
||||
[Cached]
|
||||
@@ -30,8 +33,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
private Drawable hideTarget => hudOverlay.KeyCounter;
|
||||
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First();
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage));
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always));
|
||||
|
||||
[Test]
|
||||
public void TestComboCounterIncrementing()
|
||||
@@ -84,11 +93,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
createNew();
|
||||
|
||||
HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay;
|
||||
|
||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
|
||||
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||
AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||
|
||||
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
||||
|
||||
@@ -97,37 +102,28 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft));
|
||||
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
||||
|
||||
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExternalHideDoesntAffectConfig()
|
||||
{
|
||||
HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay;
|
||||
|
||||
createNew();
|
||||
|
||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
|
||||
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||
AddAssert("config unchanged", () => originalConfigValue == config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
AddAssert("config unchanged", () => localConfig.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode).IsDefault);
|
||||
|
||||
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||
AddAssert("config unchanged", () => originalConfigValue == config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
AddAssert("config unchanged", () => localConfig.GetBindable<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode).IsDefault);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangeHUDVisibilityOnHiddenKeyCounter()
|
||||
{
|
||||
bool keyCounterVisibleValue = false;
|
||||
|
||||
createNew();
|
||||
AddStep("save keycounter visible value", () => keyCounterVisibleValue = config.Get<bool>(OsuSetting.KeyOverlay));
|
||||
|
||||
AddStep("set keycounter visible false", () =>
|
||||
AddStep("hide key overlay", () =>
|
||||
{
|
||||
config.SetValue(OsuSetting.KeyOverlay, false);
|
||||
localConfig.SetValue(OsuSetting.KeyOverlay, false);
|
||||
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
|
||||
});
|
||||
|
||||
@@ -138,8 +134,20 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
|
||||
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
|
||||
}
|
||||
|
||||
AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
|
||||
[Test]
|
||||
public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad()
|
||||
{
|
||||
AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||
|
||||
createNew();
|
||||
|
||||
AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded);
|
||||
AddUntilStep("wait for components to be hidden", () => !hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().IsPresent);
|
||||
|
||||
AddStep("reload components", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().Reload());
|
||||
AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType<SkinnableTargetContainer>().Single().ComponentsLoaded);
|
||||
}
|
||||
|
||||
private void createNew(Action<HUDOverlay> action = null)
|
||||
@@ -158,5 +166,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
Child = hudOverlay;
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
localConfig?.Dispose();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
@@ -66,7 +65,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
protected class OverlayTestPlayer : TestPlayer
|
||||
{
|
||||
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
||||
public new Bindable<bool> LocalUserPlaying => base.LocalUserPlaying;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,14 +74,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestAddControlPoint()
|
||||
{
|
||||
AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100))));
|
||||
AddStep("add point", () => path.ControlPoints.Add(new PathControlPoint { Position = { Value = new Vector2(100) } }));
|
||||
AddStep("add point", () => path.ControlPoints.Add(new PathControlPoint { Position = new Vector2(100) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInsertControlPoint()
|
||||
{
|
||||
AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(100))));
|
||||
AddStep("insert point", () => path.ControlPoints.Insert(1, new PathControlPoint { Position = { Value = new Vector2(0, 100) } }));
|
||||
AddStep("insert point", () => path.ControlPoints.Insert(1, new PathControlPoint { Position = new Vector2(0, 100) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -95,14 +95,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public void TestChangePathType()
|
||||
{
|
||||
AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100))));
|
||||
AddStep("change type to bezier", () => path.ControlPoints[0].Type.Value = PathType.Bezier);
|
||||
AddStep("change type to bezier", () => path.ControlPoints[0].Type = PathType.Bezier);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddSegmentByChangingType()
|
||||
{
|
||||
AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0))));
|
||||
AddStep("change second point type to bezier", () => path.ControlPoints[1].Type.Value = PathType.Bezier);
|
||||
AddStep("change second point type to bezier", () => path.ControlPoints[1].Type = PathType.Bezier);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -111,10 +111,10 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("create path", () =>
|
||||
{
|
||||
path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0)));
|
||||
path.ControlPoints[1].Type.Value = PathType.Bezier;
|
||||
path.ControlPoints[1].Type = PathType.Bezier;
|
||||
});
|
||||
|
||||
AddStep("change second point type to null", () => path.ControlPoints[1].Type.Value = null);
|
||||
AddStep("change second point type to null", () => path.ControlPoints[1].Type = null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("create path", () =>
|
||||
{
|
||||
path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0)));
|
||||
path.ControlPoints[1].Type.Value = PathType.Bezier;
|
||||
path.ControlPoints[1].Type = PathType.Bezier;
|
||||
});
|
||||
|
||||
AddStep("remove second point", () => path.ControlPoints.RemoveAt(1));
|
||||
@@ -185,8 +185,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private List<PathControlPoint> createSegment(PathType type, params Vector2[] controlPoints)
|
||||
{
|
||||
var points = controlPoints.Select(p => new PathControlPoint { Position = { Value = p } }).ToList();
|
||||
points[0].Type.Value = type;
|
||||
var points = controlPoints.Select(p => new PathControlPoint { Position = p }).ToList();
|
||||
points[0].Type = type;
|
||||
return points;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ using osu.Game.Database;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Tests.Visual.Navigation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
|
||||
@@ -1,10 +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 System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Tests.Visual.Navigation;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Menus
|
||||
{
|
||||
@@ -22,21 +25,48 @@ namespace osu.Game.Tests.Visual.Menus
|
||||
[Test]
|
||||
public void TestScreenOffsettingOnSettingsOverlay()
|
||||
{
|
||||
AddStep("open settings", () => Game.Settings.Show());
|
||||
AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO);
|
||||
foreach (var scalingMode in Enum.GetValues(typeof(ScalingMode)).Cast<ScalingMode>())
|
||||
{
|
||||
AddStep($"set scaling mode to {scalingMode}", () =>
|
||||
{
|
||||
Game.LocalConfig.SetValue(OsuSetting.Scaling, scalingMode);
|
||||
|
||||
AddStep("hide settings", () => Game.Settings.Hide());
|
||||
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
|
||||
if (scalingMode != ScalingMode.Off)
|
||||
{
|
||||
Game.LocalConfig.SetValue(OsuSetting.ScalingSizeX, 0.5f);
|
||||
Game.LocalConfig.SetValue(OsuSetting.ScalingSizeY, 0.5f);
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("open settings", () => Game.Settings.Show());
|
||||
AddUntilStep("right screen offset applied", () => Precision.AlmostEquals(Game.ScreenOffsetContainer.X, SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO));
|
||||
|
||||
AddStep("hide settings", () => Game.Settings.Hide());
|
||||
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScreenOffsettingOnNotificationOverlay()
|
||||
{
|
||||
AddStep("open notifications", () => Game.Notifications.Show());
|
||||
AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO);
|
||||
foreach (var scalingMode in Enum.GetValues(typeof(ScalingMode)).Cast<ScalingMode>())
|
||||
{
|
||||
if (scalingMode != ScalingMode.Off)
|
||||
{
|
||||
AddStep($"set scaling mode to {scalingMode}", () =>
|
||||
{
|
||||
Game.LocalConfig.SetValue(OsuSetting.Scaling, scalingMode);
|
||||
Game.LocalConfig.SetValue(OsuSetting.ScalingSizeX, 0.5f);
|
||||
Game.LocalConfig.SetValue(OsuSetting.ScalingSizeY, 0.5f);
|
||||
});
|
||||
}
|
||||
|
||||
AddStep("hide notifications", () => Game.Notifications.Hide());
|
||||
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
|
||||
AddStep("open notifications", () => Game.Notifications.Show());
|
||||
AddUntilStep("right screen offset applied", () => Precision.AlmostEquals(Game.ScreenOffsetContainer.X, -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO));
|
||||
|
||||
AddStep("hide notifications", () => Game.Notifications.Hide());
|
||||
AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Mods
|
||||
{
|
||||
public class TestSceneModFailCondition : ModTestScene
|
||||
{
|
||||
private bool restartRequested;
|
||||
|
||||
protected override Ruleset CreatePlayerRuleset() => new OsuRuleset();
|
||||
|
||||
protected override TestPlayer CreateModPlayer(Ruleset ruleset)
|
||||
{
|
||||
var player = base.CreateModPlayer(ruleset);
|
||||
player.RestartRequested = () => restartRequested = true;
|
||||
return player;
|
||||
}
|
||||
|
||||
protected override bool AllowFail => true;
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUp()
|
||||
{
|
||||
AddStep("reset flag", () => restartRequested = false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRestartOnFailDisabled() => CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Mod = new OsuModSuddenDeath(),
|
||||
PassCondition = () => !restartRequested && Player.ChildrenOfType<FailOverlay>().Single().State.Value == Visibility.Visible
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestRestartOnFailEnabled() => CreateModTest(new ModTestData
|
||||
{
|
||||
Autoplay = false,
|
||||
Mod = new OsuModSuddenDeath
|
||||
{
|
||||
Restart = { Value = true }
|
||||
},
|
||||
PassCondition = () => restartRequested && Player.ChildrenOfType<FailOverlay>().Single().State.Value == Visibility.Hidden
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,11 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Online.Rooms.RoomStatuses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
@@ -24,12 +24,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneDrawableRoom : OsuTestScene
|
||||
{
|
||||
[Cached]
|
||||
private readonly Bindable<Room> selectedRoom = new Bindable<Room>();
|
||||
|
||||
[Cached]
|
||||
protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
|
||||
|
||||
private readonly Bindable<Room> selectedRoom = new Bindable<Room>();
|
||||
|
||||
[Test]
|
||||
public void TestMultipleStatuses()
|
||||
{
|
||||
@@ -108,12 +107,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
EndDate = { Value = DateTimeOffset.Now },
|
||||
}),
|
||||
createDrawableRoom(new Room
|
||||
{
|
||||
Name = { Value = "Room 4 (realtime)" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Category = { Value = RoomCategory.Realtime },
|
||||
}),
|
||||
createDrawableRoom(new Room
|
||||
{
|
||||
Name = { Value = "Room 4 (spotlight)" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
@@ -134,7 +127,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
Name = { Value = "Room with password" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
Category = { Value = RoomCategory.Realtime },
|
||||
Type = { Value = MatchType.HeadToHead },
|
||||
}));
|
||||
|
||||
AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType<DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
|
||||
@@ -159,10 +152,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}));
|
||||
}
|
||||
|
||||
var drawableRoom = new DrawableRoom(room) { MatchingFilter = true };
|
||||
drawableRoom.Action = () => drawableRoom.State = drawableRoom.State == SelectionState.Selected ? SelectionState.NotSelected : SelectionState.Selected;
|
||||
|
||||
return drawableRoom;
|
||||
return new DrawableLoungeRoom(room)
|
||||
{
|
||||
MatchingFilter = true,
|
||||
SelectedRoom = { BindTarget = selectedRoom }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// 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 Moq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneGameplayChatDisplay : MultiplayerTestScene
|
||||
{
|
||||
private GameplayChatDisplay chatDisplay;
|
||||
|
||||
[Cached(typeof(ILocalUserPlayInfo))]
|
||||
private ILocalUserPlayInfo localUserInfo;
|
||||
|
||||
private readonly Bindable<bool> localUserPlaying = new Bindable<bool>();
|
||||
|
||||
private TextBox textBox => chatDisplay.ChildrenOfType<TextBox>().First();
|
||||
|
||||
public TestSceneGameplayChatDisplay()
|
||||
{
|
||||
var mockLocalUserInfo = new Mock<ILocalUserPlayInfo>();
|
||||
mockLocalUserInfo.SetupGet(i => i.IsPlaying).Returns(localUserPlaying);
|
||||
|
||||
localUserInfo = mockLocalUserInfo.Object;
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("load chat display", () => Child = chatDisplay = new GameplayChatDisplay(SelectedRoom.Value)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 0.5f,
|
||||
});
|
||||
|
||||
AddStep("expand", () => chatDisplay.Expanded.Value = true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCantClickWhenPlaying()
|
||||
{
|
||||
setLocalUserPlaying(true);
|
||||
|
||||
AddStep("attempt focus chat", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(textBox);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
assertChatFocused(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFocusDroppedWhenPlaying()
|
||||
{
|
||||
assertChatFocused(false);
|
||||
|
||||
AddStep("focus chat", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(textBox);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
setLocalUserPlaying(true);
|
||||
assertChatFocused(false);
|
||||
|
||||
// should still stay non-focused even after entering a new break section.
|
||||
setLocalUserPlaying(false);
|
||||
assertChatFocused(false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFocusOnTabKeyWhenExpanded()
|
||||
{
|
||||
setLocalUserPlaying(true);
|
||||
|
||||
assertChatFocused(false);
|
||||
AddStep("press tab", () => InputManager.Key(Key.Tab));
|
||||
assertChatFocused(true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFocusOnTabKeyWhenNotExpanded()
|
||||
{
|
||||
AddStep("set not expanded", () => chatDisplay.Expanded.Value = false);
|
||||
AddUntilStep("is not visible", () => !chatDisplay.IsPresent);
|
||||
|
||||
AddStep("press tab", () => InputManager.Key(Key.Tab));
|
||||
assertChatFocused(true);
|
||||
AddUntilStep("is visible", () => chatDisplay.IsPresent);
|
||||
|
||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||
assertChatFocused(false);
|
||||
AddUntilStep("is not visible", () => !chatDisplay.IsPresent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFocusToggleViaAction()
|
||||
{
|
||||
AddStep("set not expanded", () => chatDisplay.Expanded.Value = false);
|
||||
AddUntilStep("is not visible", () => !chatDisplay.IsPresent);
|
||||
|
||||
AddStep("press tab", () => InputManager.Key(Key.Tab));
|
||||
assertChatFocused(true);
|
||||
AddUntilStep("is visible", () => chatDisplay.IsPresent);
|
||||
|
||||
AddStep("press tab", () => InputManager.Key(Key.Tab));
|
||||
assertChatFocused(false);
|
||||
AddUntilStep("is not visible", () => !chatDisplay.IsPresent);
|
||||
}
|
||||
|
||||
private void assertChatFocused(bool isFocused) =>
|
||||
AddAssert($"chat {(isFocused ? "focused" : "not focused")}", () => textBox.HasFocus == isFocused);
|
||||
|
||||
private void setLocalUserPlaying(bool playing) =>
|
||||
AddStep($"local user {(playing ? "playing" : "not playing")}", () => localUserPlaying.Value = playing);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
using osuTK.Input;
|
||||
@@ -17,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneLoungeRoomsContainer : OnlinePlayTestScene
|
||||
{
|
||||
protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager;
|
||||
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
|
||||
|
||||
private RoomsContainer container;
|
||||
|
||||
@@ -29,6 +30,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 0.5f,
|
||||
SelectedRoom = { BindTarget = SelectedRoom }
|
||||
};
|
||||
});
|
||||
|
||||
@@ -38,7 +40,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("add rooms", () => RoomManager.AddRooms(3));
|
||||
|
||||
AddAssert("has 3 rooms", () => container.Rooms.Count == 3);
|
||||
AddStep("remove first room", () => RoomManager.Rooms.Remove(RoomManager.Rooms.FirstOrDefault()));
|
||||
AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.FirstOrDefault()));
|
||||
AddAssert("has 2 rooms", () => container.Rooms.Count == 2);
|
||||
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
|
||||
|
||||
@@ -74,7 +76,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
var room = RoomManager.Rooms[1];
|
||||
|
||||
RoomManager.RemoveRoom(room);
|
||||
RoomManager.AddRoom(room);
|
||||
RoomManager.AddOrUpdateRoom(room);
|
||||
});
|
||||
|
||||
AddAssert("no selection", () => checkRoomSelected(null));
|
||||
@@ -115,11 +117,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4);
|
||||
|
||||
AddStep("filter one room", () => container.Filter(new FilterCriteria { SearchString = "1" }));
|
||||
AddStep("filter one room", () => container.Filter.Value = new FilterCriteria { SearchString = "1" });
|
||||
|
||||
AddUntilStep("1 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 1);
|
||||
|
||||
AddStep("remove filter", () => container.Filter(null));
|
||||
AddStep("remove filter", () => container.Filter.Value = null);
|
||||
|
||||
AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4);
|
||||
}
|
||||
@@ -131,13 +133,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("add rooms", () => RoomManager.AddRooms(3, new CatchRuleset().RulesetInfo));
|
||||
|
||||
// Todo: What even is this case...?
|
||||
AddStep("set empty filter criteria", () => container.Filter(null));
|
||||
AddStep("set empty filter criteria", () => container.Filter.Value = null);
|
||||
AddUntilStep("5 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 5);
|
||||
|
||||
AddStep("filter osu! rooms", () => container.Filter(new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo }));
|
||||
AddStep("filter osu! rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo });
|
||||
AddUntilStep("2 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 2);
|
||||
|
||||
AddStep("filter catch rooms", () => container.Filter(new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo }));
|
||||
AddStep("filter catch rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo });
|
||||
AddUntilStep("3 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 3);
|
||||
}
|
||||
|
||||
@@ -150,6 +152,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
private bool checkRoomSelected(Room room) => SelectedRoom.Value == room;
|
||||
|
||||
private Room getRoomInFlow(int index) =>
|
||||
(container.ChildrenOfType<FillFlowContainer<DrawableRoom>>().First().FlowingChildren.ElementAt(index) as DrawableRoom)?.Room;
|
||||
(container.ChildrenOfType<FillFlowContainer<DrawableLoungeRoom>>().First().FlowingChildren.ElementAt(index) as DrawableRoom)?.Room;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +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 NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMatchHeader : OnlinePlayTestScene
|
||||
{
|
||||
[SetUp]
|
||||
public new void Setup() => Schedule(() =>
|
||||
{
|
||||
SelectedRoom.Value = new Room
|
||||
{
|
||||
Name = { Value = "A very awesome room" },
|
||||
Host = { Value = new User { Id = 2, Username = "peppy" } },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem
|
||||
{
|
||||
Beatmap =
|
||||
{
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "Title",
|
||||
Artist = "Artist",
|
||||
AuthorString = "Author",
|
||||
},
|
||||
Version = "Version",
|
||||
Ruleset = new OsuRuleset().RulesetInfo
|
||||
}
|
||||
},
|
||||
RequiredMods =
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModNoFail(),
|
||||
new OsuModRelax(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Child = new Header();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,17 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
using osu.Game.Users;
|
||||
|
||||
@@ -23,6 +27,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Resolved]
|
||||
private OsuGameBase game { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
@@ -80,6 +87,32 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddWaitStep("wait a bit", 20);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSpectatorPlayerInteractiveElementsHidden()
|
||||
{
|
||||
HUDVisibilityMode originalConfigValue = default;
|
||||
|
||||
AddStep("get original config hud visibility", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
AddStep("set config hud visibility to always", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always));
|
||||
|
||||
start(new[] { PLAYER_1_ID, PLAYER_2_ID });
|
||||
loadSpectateScreen(false);
|
||||
|
||||
AddUntilStep("wait for player loaders", () => this.ChildrenOfType<PlayerLoader>().Count() == 2);
|
||||
AddAssert("all player loader settings hidden", () => this.ChildrenOfType<PlayerLoader>().All(l => !l.ChildrenOfType<FillFlowContainer<PlayerSettingsGroup>>().Any()));
|
||||
|
||||
AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded);
|
||||
|
||||
// components wrapped in skinnable target containers load asynchronously, potentially taking more than one frame to load.
|
||||
// therefore use until step rather than direct assert to account for that.
|
||||
AddUntilStep("all interactive elements removed", () => this.ChildrenOfType<Player>().All(p =>
|
||||
!p.ChildrenOfType<PlayerSettingsOverlay>().Any() &&
|
||||
!p.ChildrenOfType<HoldForMenuButton>().Any() &&
|
||||
p.ChildrenOfType<SongProgressBar>().SingleOrDefault()?.ShowHandle == false));
|
||||
|
||||
AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTeamDisplay()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -12,6 +13,7 @@ using osu.Framework.Input;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@@ -28,6 +30,8 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Match;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
@@ -44,6 +48,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
private TestMultiplayer multiplayerScreen;
|
||||
private TestMultiplayerClient client;
|
||||
|
||||
private TestRequestHandlingMultiplayerRoomManager roomManager => multiplayerScreen.RoomManager;
|
||||
|
||||
[Cached(typeof(UserLookupCache))]
|
||||
private UserLookupCache lookupCache = new TestUserLookupCache();
|
||||
|
||||
@@ -68,7 +74,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("load dependencies", () =>
|
||||
{
|
||||
client = new TestMultiplayerClient(multiplayerScreen.RoomManager);
|
||||
client = new TestMultiplayerClient(roomManager);
|
||||
|
||||
// The screen gets suspended so it stops receiving updates.
|
||||
Child = client;
|
||||
@@ -90,6 +96,120 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("empty step", () => { });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLobbyEvents()
|
||||
{
|
||||
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 },
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddRepeatStep("random stuff happens", performRandomAction, 30);
|
||||
|
||||
// ensure we have a handful of players so the ready-up sounds good :9
|
||||
AddRepeatStep("player joins", addRandomPlayer, 5);
|
||||
|
||||
// all ready
|
||||
AddUntilStep("all players ready", () =>
|
||||
{
|
||||
var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
|
||||
if (nextUnready != null)
|
||||
client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
|
||||
|
||||
return client.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true;
|
||||
});
|
||||
|
||||
AddStep("unready all players at once", () =>
|
||||
{
|
||||
Debug.Assert(client.Room != null);
|
||||
|
||||
foreach (var u in client.Room.Users) client.ChangeUserState(u.UserID, MultiplayerUserState.Idle);
|
||||
});
|
||||
|
||||
AddStep("ready all players at once", () =>
|
||||
{
|
||||
Debug.Assert(client.Room != null);
|
||||
|
||||
foreach (var u in client.Room.Users) client.ChangeUserState(u.UserID, MultiplayerUserState.Ready);
|
||||
});
|
||||
}
|
||||
|
||||
private void addRandomPlayer()
|
||||
{
|
||||
int randomUser = RNG.Next(200000, 500000);
|
||||
client.AddUser(new User { Id = randomUser, Username = $"user {randomUser}" });
|
||||
}
|
||||
|
||||
private void removeLastUser()
|
||||
{
|
||||
User lastUser = client.Room?.Users.Last().User;
|
||||
|
||||
if (lastUser == null || lastUser == client.LocalUser?.User)
|
||||
return;
|
||||
|
||||
client.RemoveUser(lastUser);
|
||||
}
|
||||
|
||||
private void kickLastUser()
|
||||
{
|
||||
User lastUser = client.Room?.Users.Last().User;
|
||||
|
||||
if (lastUser == null || lastUser == client.LocalUser?.User)
|
||||
return;
|
||||
|
||||
client.KickUser(lastUser.Id);
|
||||
}
|
||||
|
||||
private void markNextPlayerReady()
|
||||
{
|
||||
var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle);
|
||||
if (nextUnready != null)
|
||||
client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready);
|
||||
}
|
||||
|
||||
private void markNextPlayerIdle()
|
||||
{
|
||||
var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Ready);
|
||||
if (nextUnready != null)
|
||||
client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Idle);
|
||||
}
|
||||
|
||||
private void performRandomAction()
|
||||
{
|
||||
int eventToPerform = RNG.Next(1, 6);
|
||||
|
||||
switch (eventToPerform)
|
||||
{
|
||||
case 1:
|
||||
addRandomPlayer();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
removeLastUser();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
kickLastUser();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
markNextPlayerReady();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
markNextPlayerIdle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateRoomViaKeyboard()
|
||||
{
|
||||
@@ -132,39 +252,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestExitMidJoin()
|
||||
{
|
||||
Room room = null;
|
||||
|
||||
AddStep("create room", () =>
|
||||
{
|
||||
room = 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 },
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
AddStep("refresh rooms", () => multiplayerScreen.RoomManager.Filter.Value = new FilterCriteria());
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("join room and immediately exit", () =>
|
||||
{
|
||||
multiplayerScreen.ChildrenOfType<LoungeSubScreen>().Single().Open(room);
|
||||
Schedule(() => Stack.CurrentScreen.Exit());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJoinRoomWithoutPassword()
|
||||
{
|
||||
AddStep("create room", () =>
|
||||
{
|
||||
multiplayerScreen.RoomManager.AddRoom(new Room
|
||||
roomManager.AddServerSideRoom(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Playlist =
|
||||
@@ -178,7 +268,39 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
});
|
||||
|
||||
AddStep("refresh rooms", () => multiplayerScreen.RoomManager.Filter.Value = new FilterCriteria());
|
||||
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
|
||||
AddUntilStep("wait for room", () => this.ChildrenOfType<DrawableRoom>().Any());
|
||||
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("join room and immediately exit select", () =>
|
||||
{
|
||||
InputManager.Key(Key.Enter);
|
||||
Schedule(() => Stack.CurrentScreen.Exit());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJoinRoomWithoutPassword()
|
||||
{
|
||||
AddStep("create room", () =>
|
||||
{
|
||||
roomManager.AddServerSideRoom(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 },
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
|
||||
AddUntilStep("wait for room", () => this.ChildrenOfType<DrawableRoom>().Any());
|
||||
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("join room", () => InputManager.Key(Key.Enter));
|
||||
|
||||
@@ -211,7 +333,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
AddStep("create room", () =>
|
||||
{
|
||||
multiplayerScreen.RoomManager.AddRoom(new Room
|
||||
roomManager.AddServerSideRoom(new Room
|
||||
{
|
||||
Name = { Value = "Test Room" },
|
||||
Password = { Value = "password" },
|
||||
@@ -226,12 +348,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
});
|
||||
|
||||
AddStep("refresh rooms", () => multiplayerScreen.RoomManager.Filter.Value = new FilterCriteria());
|
||||
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
|
||||
AddUntilStep("wait for room", () => this.ChildrenOfType<DrawableRoom>().Any());
|
||||
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("join room", () => InputManager.Key(Key.Enter));
|
||||
|
||||
DrawableRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
||||
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
||||
|
||||
@@ -424,6 +548,40 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGameplayFlow()
|
||||
{
|
||||
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 },
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddRepeatStep("click spectate button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerReadyButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
}, 2);
|
||||
|
||||
AddUntilStep("wait for player", () => Stack.CurrentScreen is Player);
|
||||
|
||||
// Gameplay runs in real-time, so we need to incrementally check if gameplay has finished in order to not time out.
|
||||
for (double i = 1000; i < TestResources.QUICK_BEATMAP_LENGTH; i += 1000)
|
||||
{
|
||||
var time = i;
|
||||
AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType<GameplayClockContainer>().SingleOrDefault()?.GameplayClock.CurrentTime > time);
|
||||
}
|
||||
|
||||
AddUntilStep("wait for results", () => Stack.CurrentScreen is ResultsScreen);
|
||||
}
|
||||
|
||||
private void createRoom(Func<Room> room)
|
||||
{
|
||||
AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType<LoungeSubScreen>().SingleOrDefault()?.IsLoaded == true);
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
using osuTK.Input;
|
||||
@@ -18,7 +17,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene
|
||||
{
|
||||
protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager;
|
||||
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
|
||||
|
||||
private LoungeSubScreen loungeScreen;
|
||||
|
||||
@@ -59,20 +58,20 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||
|
||||
AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().Any());
|
||||
AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().Any());
|
||||
AddStep("exit screen", () => Stack.Exit());
|
||||
AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().Any());
|
||||
AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJoinRoomWithPassword()
|
||||
{
|
||||
DrawableRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||
|
||||
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
||||
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
||||
|
||||
@@ -83,12 +82,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestJoinRoomWithPasswordViaKeyboardOnly()
|
||||
{
|
||||
DrawableRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||
|
||||
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
||||
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "password");
|
||||
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
@@ -89,7 +90,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
SelectedMods.SetDefault();
|
||||
});
|
||||
|
||||
AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect()));
|
||||
AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect(SelectedRoom.Value)));
|
||||
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
|
||||
}
|
||||
|
||||
@@ -168,6 +169,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
public new Bindable<IReadOnlyList<Mod>> FreeMods => base.FreeMods;
|
||||
|
||||
public new BeatmapCarousel Carousel => base.Carousel;
|
||||
|
||||
public TestMultiplayerMatchSongSelect(Room room, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null)
|
||||
: base(room, beatmap, ruleset)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,23 +59,6 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("wait for load", () => screen.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSettingValidity()
|
||||
{
|
||||
AddAssert("create button not enabled", () => !this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("set playlist", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||
});
|
||||
});
|
||||
|
||||
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreatedRoom()
|
||||
{
|
||||
@@ -97,6 +80,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("wait for join", () => Client.Room != null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSettingValidity()
|
||||
{
|
||||
AddAssert("create button not enabled", () => !this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("set playlist", () =>
|
||||
{
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo },
|
||||
});
|
||||
});
|
||||
|
||||
AddAssert("create button enabled", () => this.ChildrenOfType<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>().Single().Enabled.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStartMatchWhileSpectating()
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Testing;
|
||||
@@ -48,9 +49,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
|
||||
|
||||
AddStep("add non-resolvable user", () => Client.AddNullUser(-3));
|
||||
AddStep("add non-resolvable user", () => Client.AddNullUser());
|
||||
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
|
||||
|
||||
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
|
||||
|
||||
AddStep("kick null user", () => this.ChildrenOfType<ParticipantPanel>().Single(p => p.User.User == null)
|
||||
.ChildrenOfType<ParticipantPanel.KickButton>().Single().TriggerClick());
|
||||
|
||||
AddAssert("null user kicked", () => Client.Room.AsNonNull().Users.Count == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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.Testing;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMultiplayerPlayer : MultiplayerTestScene
|
||||
{
|
||||
private MultiplayerPlayer player;
|
||||
|
||||
[SetUpSteps]
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("set beatmap", () =>
|
||||
{
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
});
|
||||
|
||||
AddStep("initialise gameplay", () =>
|
||||
{
|
||||
Stack.Push(player = new MultiplayerPlayer(Client.APIRoom, Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray()));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGameplay()
|
||||
{
|
||||
AddUntilStep("wait for gameplay start", () => player.LocalUserPlaying.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +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 System;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Screens.OnlinePlay.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
[HeadlessTest]
|
||||
public class TestSceneMultiplayerRoomManager : MultiplayerTestScene
|
||||
{
|
||||
protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies();
|
||||
|
||||
public TestSceneMultiplayerRoomManager()
|
||||
: base(false)
|
||||
{
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPollsInitially()
|
||||
{
|
||||
AddStep("create room manager with a few rooms", () =>
|
||||
{
|
||||
RoomManager.CreateRoom(createRoom(r => r.Name.Value = "1"));
|
||||
RoomManager.PartRoom();
|
||||
RoomManager.CreateRoom(createRoom(r => r.Name.Value = "2"));
|
||||
RoomManager.PartRoom();
|
||||
RoomManager.ClearRooms();
|
||||
});
|
||||
|
||||
AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2);
|
||||
AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRoomsClearedOnDisconnection()
|
||||
{
|
||||
AddStep("create room manager with a few rooms", () =>
|
||||
{
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
RoomManager.PartRoom();
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
RoomManager.PartRoom();
|
||||
});
|
||||
|
||||
AddStep("disconnect", () => Client.Disconnect());
|
||||
|
||||
AddAssert("rooms cleared", () => ((RoomManager)RoomManager).Rooms.Count == 0);
|
||||
AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRoomsPolledOnReconnect()
|
||||
{
|
||||
AddStep("create room manager with a few rooms", () =>
|
||||
{
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
RoomManager.PartRoom();
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
RoomManager.PartRoom();
|
||||
});
|
||||
|
||||
AddStep("disconnect", () => Client.Disconnect());
|
||||
AddStep("connect", () => Client.Connect());
|
||||
|
||||
AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2);
|
||||
AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRoomsNotPolledWhenJoined()
|
||||
{
|
||||
AddStep("create room manager with a room", () =>
|
||||
{
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
RoomManager.ClearRooms();
|
||||
});
|
||||
|
||||
AddAssert("manager not polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 0);
|
||||
AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultiplayerRoomJoinedWhenCreated()
|
||||
{
|
||||
AddStep("create room manager with a room", () =>
|
||||
{
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
});
|
||||
|
||||
AddUntilStep("multiplayer room joined", () => Client.Room != null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultiplayerRoomPartedWhenAPIRoomParted()
|
||||
{
|
||||
AddStep("create room manager with a room", () =>
|
||||
{
|
||||
RoomManager.CreateRoom(createRoom());
|
||||
RoomManager.PartRoom();
|
||||
});
|
||||
|
||||
AddAssert("multiplayer room parted", () => Client.Room == null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultiplayerRoomJoinedWhenAPIRoomJoined()
|
||||
{
|
||||
AddStep("create room manager with a room", () =>
|
||||
{
|
||||
var r = createRoom();
|
||||
RoomManager.CreateRoom(r);
|
||||
RoomManager.PartRoom();
|
||||
RoomManager.JoinRoom(r);
|
||||
});
|
||||
|
||||
AddUntilStep("multiplayer room joined", () => Client.Room != null);
|
||||
}
|
||||
|
||||
private Room createRoom(Action<Room> initFunc = null)
|
||||
{
|
||||
var room = new Room
|
||||
{
|
||||
Name =
|
||||
{
|
||||
Value = "test room"
|
||||
},
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo },
|
||||
Ruleset = { Value = Ruleset.Value }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initFunc?.Invoke(room);
|
||||
return room;
|
||||
}
|
||||
|
||||
private class TestDependencies : MultiplayerTestSceneDependencies
|
||||
{
|
||||
public TestDependencies()
|
||||
{
|
||||
// Need to set these values as early as possible.
|
||||
RoomManager.TimeBetweenListingPolls.Value = 1;
|
||||
RoomManager.TimeBetweenSelectionPolls.Value = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
SelectedMods.Value = Array.Empty<Mod>();
|
||||
});
|
||||
|
||||
AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect()));
|
||||
AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect(SelectedRoom.Value)));
|
||||
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
|
||||
}
|
||||
|
||||
@@ -183,6 +183,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
private class TestPlaylistsSongSelect : PlaylistsSongSelect
|
||||
{
|
||||
public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails;
|
||||
|
||||
public TestPlaylistsSongSelect(Room room)
|
||||
: base(room)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
@@ -88,21 +89,27 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
[Resolved]
|
||||
private OsuGameBase gameBase { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
game = new OsuGame();
|
||||
game.SetHost(host);
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
Children = new Drawable[]
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("create game", () =>
|
||||
{
|
||||
new Box
|
||||
game = new OsuGame();
|
||||
game.SetHost(host);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
game
|
||||
};
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
game
|
||||
};
|
||||
});
|
||||
|
||||
AddUntilStep("wait for load", () => game.IsLoaded);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,12 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestSettingsMigration : OsuGameTestScene
|
||||
{
|
||||
public override void RecycleLocalStorage()
|
||||
public override void RecycleLocalStorage(bool isDisposing)
|
||||
{
|
||||
base.RecycleLocalStorage();
|
||||
base.RecycleLocalStorage(isDisposing);
|
||||
|
||||
if (isDisposing)
|
||||
return;
|
||||
|
||||
using (var config = new OsuConfigManager(LocalStorage))
|
||||
{
|
||||
|
||||
@@ -42,19 +42,21 @@ namespace osu.Game.Tests.Visual.Online
|
||||
() => commentsContainer.ChildrenOfType<CommentsShowMoreButton>().Single().IsLoading);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleCommentsPage()
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestSingleCommentsPage(bool withPinned)
|
||||
{
|
||||
setUpCommentsResponse(exampleComments);
|
||||
setUpCommentsResponse(getExampleComments(withPinned));
|
||||
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||
AddUntilStep("show more button hidden",
|
||||
() => commentsContainer.ChildrenOfType<CommentsShowMoreButton>().Single().Alpha == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleCommentPages()
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestMultipleCommentPages(bool withPinned)
|
||||
{
|
||||
var comments = exampleComments;
|
||||
var comments = getExampleComments(withPinned);
|
||||
comments.HasMore = true;
|
||||
comments.TopLevelCount = 10;
|
||||
|
||||
@@ -64,11 +66,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
() => commentsContainer.ChildrenOfType<CommentsShowMoreButton>().Single().Alpha == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleLoads()
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestMultipleLoads(bool withPinned)
|
||||
{
|
||||
var comments = exampleComments;
|
||||
int topLevelCommentCount = exampleComments.Comments.Count;
|
||||
var comments = getExampleComments(withPinned);
|
||||
int topLevelCommentCount = comments.Comments.Count;
|
||||
|
||||
AddStep("hide container", () => commentsContainer.Hide());
|
||||
setUpCommentsResponse(comments);
|
||||
@@ -79,6 +82,48 @@ namespace osu.Game.Tests.Visual.Online
|
||||
() => commentsContainer.ChildrenOfType<DrawableComment>().Count() == topLevelCommentCount);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoComment()
|
||||
{
|
||||
var comments = getExampleComments();
|
||||
comments.Comments.Clear();
|
||||
|
||||
setUpCommentsResponse(comments);
|
||||
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||
AddAssert("no comment shown", () => !commentsContainer.ChildrenOfType<DrawableComment>().Any());
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
public void TestSingleComment(bool withPinned)
|
||||
{
|
||||
var comment = new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "This is a single comment",
|
||||
LegacyName = "SingleUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 0,
|
||||
Pinned = withPinned,
|
||||
};
|
||||
|
||||
var bundle = new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment> { comment },
|
||||
IncludedComments = new List<Comment>(),
|
||||
PinnedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
if (withPinned)
|
||||
bundle.PinnedComments.Add(comment);
|
||||
|
||||
setUpCommentsResponse(bundle);
|
||||
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||
AddUntilStep("wait comment load", () => commentsContainer.ChildrenOfType<DrawableComment>().Any());
|
||||
AddAssert("only one comment shown", () =>
|
||||
commentsContainer.ChildrenOfType<DrawableComment>().Count(d => d.Comment.Pinned == withPinned) == 1);
|
||||
}
|
||||
|
||||
private void setUpCommentsResponse(CommentBundle commentBundle)
|
||||
=> AddStep("set up response", () =>
|
||||
{
|
||||
@@ -92,38 +137,71 @@ namespace osu.Game.Tests.Visual.Online
|
||||
};
|
||||
});
|
||||
|
||||
private CommentBundle exampleComments => new CommentBundle
|
||||
private CommentBundle getExampleComments(bool withPinned = false)
|
||||
{
|
||||
Comments = new List<Comment>
|
||||
var bundle = new CommentBundle
|
||||
{
|
||||
new Comment
|
||||
Comments = new List<Comment>
|
||||
{
|
||||
Id = 1,
|
||||
Message = "This is a comment",
|
||||
LegacyName = "FirstUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 19,
|
||||
RepliesCount = 1
|
||||
new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "This is a comment",
|
||||
LegacyName = "FirstUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 19,
|
||||
RepliesCount = 1
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 5,
|
||||
ParentId = 1,
|
||||
Message = "This is a child comment",
|
||||
LegacyName = "SecondUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 4,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 10,
|
||||
Message = "This is another comment",
|
||||
LegacyName = "ThirdUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 0
|
||||
},
|
||||
},
|
||||
new Comment
|
||||
IncludedComments = new List<Comment>(),
|
||||
PinnedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
if (withPinned)
|
||||
{
|
||||
var pinnedComment = new Comment
|
||||
{
|
||||
Id = 5,
|
||||
ParentId = 1,
|
||||
Message = "This is a child comment",
|
||||
LegacyName = "SecondUser",
|
||||
Id = 15,
|
||||
Message = "This is pinned comment",
|
||||
LegacyName = "PinnedUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 4,
|
||||
},
|
||||
new Comment
|
||||
VotesCount = 999,
|
||||
Pinned = true,
|
||||
RepliesCount = 1,
|
||||
};
|
||||
|
||||
bundle.Comments.Add(pinnedComment);
|
||||
bundle.PinnedComments.Add(pinnedComment);
|
||||
|
||||
bundle.Comments.Add(new Comment
|
||||
{
|
||||
Id = 10,
|
||||
Message = "This is another comment",
|
||||
LegacyName = "ThirdUser",
|
||||
Id = 20,
|
||||
Message = "Reply to pinned comment",
|
||||
LegacyName = "AbandonedUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 0
|
||||
},
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
};
|
||||
VotesCount = 0,
|
||||
ParentId = 15,
|
||||
});
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
AddStep(description, () =>
|
||||
{
|
||||
comment.Pinned = description == "Pinned";
|
||||
comment.Message = text;
|
||||
container.Add(new DrawableComment(comment));
|
||||
});
|
||||
@@ -59,6 +60,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
private static object[] comments =
|
||||
{
|
||||
new[] { "Plain", "This is plain comment" },
|
||||
new[] { "Pinned", "This is pinned comment" },
|
||||
new[] { "Link", "Please visit https://osu.ppy.sh" },
|
||||
|
||||
new[]
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestPlayActivity()
|
||||
{
|
||||
AddStep("Set activity", () => api.Activity.Value = new UserActivity.SoloGame(new BeatmapInfo(), new RulesetInfo()));
|
||||
AddStep("Set activity", () => api.Activity.Value = new UserActivity.InSoloGame(new BeatmapInfo(), new RulesetInfo()));
|
||||
|
||||
AddStep("Run command", () => Add(new NowPlayingCommand()));
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
PinnedComments = new List<Comment>(),
|
||||
UserVotes = new List<long>
|
||||
{
|
||||
5
|
||||
@@ -178,6 +179,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
PinnedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
private class TestCommentsContainer : CommentsContainer
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
// 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.Game.Overlays;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Users;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Rankings;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@@ -14,25 +17,29 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
||||
[Cached(typeof(RankingsOverlay))]
|
||||
private readonly RankingsOverlay rankingsOverlay;
|
||||
private TestRankingsOverlay rankingsOverlay;
|
||||
|
||||
private readonly Bindable<Country> countryBindable = new Bindable<Country>();
|
||||
private readonly Bindable<RankingsScope> scope = new Bindable<RankingsScope>();
|
||||
|
||||
public TestSceneRankingsOverlay()
|
||||
{
|
||||
Add(rankingsOverlay = new TestRankingsOverlay
|
||||
{
|
||||
Country = { BindTarget = countryBindable },
|
||||
Header = { Current = { BindTarget = scope } },
|
||||
});
|
||||
}
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(loadRankingsOverlay);
|
||||
|
||||
[Test]
|
||||
public void TestShow()
|
||||
public void TestParentRulesetDecoupledAfterInitialShow()
|
||||
{
|
||||
AddStep("Show", rankingsOverlay.Show);
|
||||
AddStep("enable global ruleset", () => Ruleset.Disabled = false);
|
||||
AddStep("set global ruleset to osu!catch", () => Ruleset.Value = new CatchRuleset().RulesetInfo);
|
||||
AddStep("reload rankings overlay", loadRankingsOverlay);
|
||||
AddAssert("rankings ruleset set to osu!catch", () => rankingsOverlay.Header.Ruleset.Value.ShortName == CatchRuleset.SHORT_NAME);
|
||||
|
||||
AddStep("set global ruleset to osu!", () => Ruleset.Value = new OsuRuleset().RulesetInfo);
|
||||
AddAssert("rankings ruleset still osu!catch", () => rankingsOverlay.Header.Ruleset.Value.ShortName == CatchRuleset.SHORT_NAME);
|
||||
|
||||
AddStep("disable global ruleset", () => Ruleset.Disabled = true);
|
||||
AddAssert("rankings ruleset still enabled", () => rankingsOverlay.Header.Ruleset.Disabled == false);
|
||||
AddStep("set rankings ruleset to osu!mania", () => rankingsOverlay.Header.Ruleset.Value = new ManiaRuleset().RulesetInfo);
|
||||
AddAssert("rankings ruleset set to osu!mania", () => rankingsOverlay.Header.Ruleset.Value.ShortName == ManiaRuleset.SHORT_NAME);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -50,10 +57,14 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep("Show US", () => rankingsOverlay.ShowCountry(us_country));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHide()
|
||||
private void loadRankingsOverlay()
|
||||
{
|
||||
AddStep("Hide", rankingsOverlay.Hide);
|
||||
Child = rankingsOverlay = new TestRankingsOverlay
|
||||
{
|
||||
Country = { BindTarget = countryBindable },
|
||||
Header = { Current = { BindTarget = scope } },
|
||||
State = { Value = Visibility.Visible },
|
||||
};
|
||||
}
|
||||
|
||||
private static readonly Country us_country = new Country
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("visit message is not visible", () => !evast.LastVisitMessage.IsPresent);
|
||||
}
|
||||
|
||||
private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.SoloGame(null, rulesetStore.GetRuleset(rulesetId));
|
||||
private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.InSoloGame(null, rulesetStore.GetRuleset(rulesetId));
|
||||
|
||||
private class TestUserListPanel : UserListPanel
|
||||
{
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Playlists;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
@@ -16,15 +17,15 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
public class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene
|
||||
{
|
||||
protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager;
|
||||
protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager;
|
||||
|
||||
private LoungeSubScreen loungeScreen;
|
||||
private TestLoungeSubScreen loungeScreen;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("push screen", () => LoadScreen(loungeScreen = new PlaylistsLoungeSubScreen()));
|
||||
AddStep("push screen", () => LoadScreen(loungeScreen = new TestLoungeSubScreen()));
|
||||
|
||||
AddUntilStep("wait for present", () => loungeScreen.IsCurrentScreen());
|
||||
}
|
||||
@@ -37,6 +38,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
AddStep("reset mouse", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
|
||||
AddStep("add rooms", () => RoomManager.AddRooms(30));
|
||||
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30);
|
||||
|
||||
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
|
||||
|
||||
@@ -53,6 +55,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
public void TestScrollSelectedIntoView()
|
||||
{
|
||||
AddStep("add rooms", () => RoomManager.AddRooms(30));
|
||||
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30);
|
||||
|
||||
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
|
||||
|
||||
@@ -67,21 +70,26 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
AddStep("add rooms", () => RoomManager.AddRooms(1));
|
||||
|
||||
AddAssert("selected room is not disabled", () => !OnlinePlayDependencies.SelectedRoom.Disabled);
|
||||
AddAssert("selected room is not disabled", () => !loungeScreen.SelectedRoom.Disabled);
|
||||
|
||||
AddStep("select room", () => roomsContainer.Rooms[0].TriggerClick());
|
||||
AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null);
|
||||
AddAssert("selected room is non-null", () => loungeScreen.SelectedRoom.Value != null);
|
||||
|
||||
AddStep("enter room", () => roomsContainer.Rooms[0].TriggerClick());
|
||||
|
||||
AddUntilStep("wait for match load", () => Stack.CurrentScreen is PlaylistsRoomSubScreen);
|
||||
|
||||
AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null);
|
||||
AddAssert("selected room is disabled", () => OnlinePlayDependencies.SelectedRoom.Disabled);
|
||||
AddAssert("selected room is non-null", () => loungeScreen.SelectedRoom.Value != null);
|
||||
AddAssert("selected room is disabled", () => loungeScreen.SelectedRoom.Disabled);
|
||||
}
|
||||
|
||||
private bool checkRoomVisible(DrawableRoom room) =>
|
||||
loungeScreen.ChildrenOfType<OsuScrollContainer>().First().ScreenSpaceDrawQuad
|
||||
.Contains(room.ScreenSpaceDrawQuad.Centre);
|
||||
|
||||
private class TestLoungeSubScreen : PlaylistsLoungeSubScreen
|
||||
{
|
||||
public new Bindable<Room> SelectedRoom => base.SelectedRoom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
SelectedRoom.Value = new Room();
|
||||
|
||||
Child = settings = new TestRoomSettings
|
||||
Child = settings = new TestRoomSettings(SelectedRoom.Value)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = { Value = Visibility.Visible }
|
||||
@@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent);
|
||||
}
|
||||
|
||||
private class TestRoomSettings : PlaylistsMatchSettingsOverlay
|
||||
private class TestRoomSettings : PlaylistsRoomSettingsOverlay
|
||||
{
|
||||
public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton;
|
||||
|
||||
@@ -118,6 +118,11 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
public OsuDropdown<TimeSpan> DurationField => ((MatchSettings)Settings).DurationField;
|
||||
|
||||
public OsuSpriteText ErrorText => ((MatchSettings)Settings).ErrorText;
|
||||
|
||||
public TestRoomSettings(Room room)
|
||||
: base(room)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDependencies : OnlinePlayTestSceneDependencies
|
||||
@@ -141,6 +146,12 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
public IBindableList<Room> Rooms => null;
|
||||
|
||||
public void AddOrUpdateRoom(Room room) => throw new NotImplementedException();
|
||||
|
||||
public void RemoveRoom(Room room) => throw new NotImplementedException();
|
||||
|
||||
public void ClearRooms() => throw new NotImplementedException();
|
||||
|
||||
public void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null)
|
||||
{
|
||||
if (CreateRequested == null)
|
||||
|
||||
@@ -11,7 +11,6 @@ using osu.Framework.Platform;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
@@ -19,7 +18,6 @@ using osu.Game.Screens.OnlinePlay.Playlists;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Playlists
|
||||
@@ -36,18 +34,6 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
|
||||
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
|
||||
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case CreateRoomScoreRequest createRoomScoreRequest:
|
||||
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
@@ -66,7 +52,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
SelectedRoom.Value.RoomID.Value = 1;
|
||||
SelectedRoom.Value.Name.Value = "my awesome room";
|
||||
SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" };
|
||||
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
|
||||
SelectedRoom.Value.RecentParticipants.Add(SelectedRoom.Value.Host.Value);
|
||||
SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||
@@ -86,7 +72,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
AddStep("set room properties", () =>
|
||||
{
|
||||
SelectedRoom.Value.Name.Value = "my awesome room";
|
||||
SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" };
|
||||
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
|
||||
@@ -96,7 +82,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
AddStep("move mouse to create button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsMatchSettingsOverlay.CreateRoomButton>().Single());
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
|
||||
});
|
||||
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
@@ -137,7 +123,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
AddStep("load room", () =>
|
||||
{
|
||||
SelectedRoom.Value.Name.Value = "my awesome room";
|
||||
SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" };
|
||||
SelectedRoom.Value.Host.Value = API.LocalUser.Value;
|
||||
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = importedSet.Beatmaps[0] },
|
||||
@@ -147,7 +133,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
AddStep("create room", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(match.ChildrenOfType<PlaylistsMatchSettingsOverlay.CreateRoomButton>().Single());
|
||||
InputManager.MoveMouseTo(match.ChildrenOfType<PlaylistsRoomSettingsOverlay.CreateRoomButton>().Single());
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,65 +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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
public class TestSceneStarRatingDisplay : OsuTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestDisplay()
|
||||
{
|
||||
AddStep("load displays", () => Child = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ChildrenEnumerable = new[]
|
||||
{
|
||||
1.23,
|
||||
2.34,
|
||||
3.45,
|
||||
4.56,
|
||||
5.67,
|
||||
6.78,
|
||||
10.11,
|
||||
}.Select(starRating => new StarRatingDisplay(new StarDifficulty(starRating, 0))
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangingStarRatingDisplay()
|
||||
{
|
||||
StarRatingDisplay starRating = null;
|
||||
|
||||
AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1))
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(3f),
|
||||
});
|
||||
|
||||
AddRepeatStep("set random value", () =>
|
||||
{
|
||||
starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1);
|
||||
}, 10);
|
||||
|
||||
AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d =>
|
||||
{
|
||||
if (starRating != null)
|
||||
starRating.Current.Value = new StarDifficulty(d, 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddUntilStep("wait for load", () => panel.ChildrenOfType<GlobalKeyBindingsSection>().Any());
|
||||
AddStep("Scroll to top", () => panel.ChildrenOfType<SettingsPanel.SettingsSectionsContainer>().First().ScrollToTop());
|
||||
AddWaitStep("wait for scroll", 5);
|
||||
}
|
||||
|
||||
@@ -76,5 +76,23 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
AddStep("restore default", () => sliderBar.Current.SetDefault());
|
||||
AddUntilStep("restore button hidden", () => restoreDefaultValueButton.Alpha == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWarningTextVisibility()
|
||||
{
|
||||
SettingsNumberBox numberBox = null;
|
||||
|
||||
AddStep("create settings item", () => Child = numberBox = new SettingsNumberBox());
|
||||
AddAssert("warning text not created", () => !numberBox.ChildrenOfType<SettingsNoticeText>().Any());
|
||||
|
||||
AddStep("set warning text", () => numberBox.WarningText = "this is a warning!");
|
||||
AddAssert("warning text created", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 1);
|
||||
|
||||
AddStep("unset warning text", () => numberBox.WarningText = default);
|
||||
AddAssert("warning text hidden", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 0);
|
||||
|
||||
AddStep("set warning text again", () => numberBox.WarningText = "another warning!");
|
||||
AddAssert("warning text shown again", () => numberBox.ChildrenOfType<SettingsNoticeText>().Single().Alpha == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Settings
|
||||
@@ -11,27 +12,39 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
[TestFixture]
|
||||
public class TestSceneSettingsPanel : OsuTestScene
|
||||
{
|
||||
private readonly SettingsPanel settings;
|
||||
private readonly DialogOverlay dialogOverlay;
|
||||
private SettingsPanel settings;
|
||||
private DialogOverlay dialogOverlay;
|
||||
|
||||
public TestSceneSettingsPanel()
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
settings = new SettingsOverlay
|
||||
AddStep("create settings", () =>
|
||||
{
|
||||
State = { Value = Visibility.Visible }
|
||||
};
|
||||
Add(dialogOverlay = new DialogOverlay
|
||||
{
|
||||
Depth = -1
|
||||
settings?.Expire();
|
||||
|
||||
Add(settings = new SettingsOverlay
|
||||
{
|
||||
State = { Value = Visibility.Visible }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToggleVisibility()
|
||||
{
|
||||
AddWaitStep("wait some", 5);
|
||||
AddToggleStep("toggle editor visibility", visible => settings.ToggleVisibility());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Dependencies.Cache(dialogOverlay);
|
||||
Add(dialogOverlay = new DialogOverlay
|
||||
{
|
||||
Depth = -1
|
||||
});
|
||||
|
||||
Add(settings);
|
||||
Dependencies.Cache(dialogOverlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
@@ -18,6 +21,7 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Screens.Select;
|
||||
using osuTK;
|
||||
@@ -65,6 +69,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("show", () => { infoWedge.Show(); });
|
||||
|
||||
AddSliderStep("change star difficulty", 0, 11.9, 5.55, v =>
|
||||
{
|
||||
foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType<IHasCurrentValue<StarDifficulty>>())
|
||||
hasCurrentValue.Current.Value = new StarDifficulty(v, 0);
|
||||
});
|
||||
|
||||
foreach (var rulesetInfo in rulesets.AvailableRulesets)
|
||||
{
|
||||
var instance = rulesetInfo.CreateInstance();
|
||||
@@ -134,6 +144,29 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
selectBeatmap(createLongMetadata());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBPMUpdates()
|
||||
{
|
||||
const float bpm = 120;
|
||||
IBeatmap beatmap = createTestBeatmap(new OsuRuleset().RulesetInfo);
|
||||
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm });
|
||||
|
||||
OsuModDoubleTime doubleTime = null;
|
||||
|
||||
selectBeatmap(beatmap);
|
||||
checkDisplayedBPM(bpm);
|
||||
|
||||
AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() });
|
||||
checkDisplayedBPM(bpm * 1.5f);
|
||||
|
||||
AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2);
|
||||
checkDisplayedBPM(bpm * 2);
|
||||
|
||||
void checkDisplayedBPM(float target) =>
|
||||
AddUntilStep($"displayed bpm is {target}", () => this.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Any(
|
||||
label => label.Statistic.Name == "BPM" && label.Statistic.Content == target.ToString(CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
private void selectBeatmap([CanBeNull] IBeatmap b)
|
||||
{
|
||||
Container containerBefore = null;
|
||||
|
||||
@@ -14,7 +14,6 @@ using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Tests.Visual.Navigation;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
@@ -174,6 +176,60 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
checkBindableAtValue("Circle Size", null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestModSettingChangeTracker()
|
||||
{
|
||||
ModSettingChangeTracker tracker = null;
|
||||
Queue<Mod> settingsChangedQueue = null;
|
||||
|
||||
setBeatmapWithDifficultyParameters(5);
|
||||
|
||||
AddStep("add mod settings change tracker", () =>
|
||||
{
|
||||
settingsChangedQueue = new Queue<Mod>();
|
||||
|
||||
tracker = new ModSettingChangeTracker(modDifficultyAdjust.Yield())
|
||||
{
|
||||
SettingChanged = settingsChangedQueue.Enqueue
|
||||
};
|
||||
});
|
||||
|
||||
AddAssert("no settings changed", () => settingsChangedQueue.Count == 0);
|
||||
|
||||
setSliderValue("Circle Size", 3);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
setSliderValue("Circle Size", 5);
|
||||
checkBindableAtValue("Circle Size", 5);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
AddStep("reset mod settings", () => modDifficultyAdjust.CircleSize.SetDefault());
|
||||
checkBindableAtValue("Circle Size", null);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
setExtendedLimits(true);
|
||||
|
||||
settingsChangedFired();
|
||||
|
||||
AddStep("dispose tracker", () =>
|
||||
{
|
||||
tracker.Dispose();
|
||||
tracker = null;
|
||||
});
|
||||
|
||||
void settingsChangedFired()
|
||||
{
|
||||
AddAssert("setting changed event fired", () =>
|
||||
{
|
||||
settingsChangedQueue.Dequeue();
|
||||
return settingsChangedQueue.Count == 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void resetToDefault(string name)
|
||||
{
|
||||
AddStep($"Reset {name} to default", () =>
|
||||
|
||||
@@ -6,6 +6,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@@ -61,10 +62,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
));
|
||||
AddStep("scroll up", () => triggerUserScroll(1));
|
||||
AddStep("scroll down", () => triggerUserScroll(-1));
|
||||
AddStep("scroll up a bit", () => triggerUserScroll(0.1f));
|
||||
AddStep("scroll down a bit", () => triggerUserScroll(-0.1f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCorrectSectionSelected()
|
||||
public void TestCorrectSelectionAndVisibleTop()
|
||||
{
|
||||
const int sections_count = 11;
|
||||
float[] alternating = { 0.07f, 0.33f, 0.16f, 0.33f };
|
||||
@@ -79,6 +82,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
AddStep($"scroll to section {scrollIndex + 1}", () => container.ScrollTo(container.Children[scrollIndex]));
|
||||
AddUntilStep("correct section selected", () => container.SelectedSection.Value == container.Children[scrollIndex]);
|
||||
AddUntilStep("section top is visible", () =>
|
||||
{
|
||||
float scrollPosition = container.ChildrenOfType<UserTrackingScrollContainer>().First().Current;
|
||||
float sectionTop = container.Children[scrollIndex].BoundingBox.Top;
|
||||
return scrollPosition < sectionTop;
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 1; i < sections_count; i++)
|
||||
|
||||
@@ -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 System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneStarRatingDisplay : OsuTestScene
|
||||
{
|
||||
[TestCase(StarRatingDisplaySize.Regular)]
|
||||
[TestCase(StarRatingDisplaySize.Small)]
|
||||
public void TestDisplay(StarRatingDisplaySize size)
|
||||
{
|
||||
AddStep("load displays", () =>
|
||||
{
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(2f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
ChildrenEnumerable = Enumerable.Range(0, 15).Select(i => new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(2f),
|
||||
Direction = FillDirection.Vertical,
|
||||
ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i * (i >= 11 ? 25f : 1f) + j * 0.1f, 0), size)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}),
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSpectrum()
|
||||
{
|
||||
StarRatingDisplay starRating = null;
|
||||
|
||||
AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1), animated: true)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(3f),
|
||||
});
|
||||
|
||||
AddRepeatStep("set random value", () =>
|
||||
{
|
||||
starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1);
|
||||
}, 10);
|
||||
|
||||
AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d =>
|
||||
{
|
||||
if (starRating != null)
|
||||
starRating.Current.Value = new StarDifficulty(d, 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ namespace osu.Game.Tests
|
||||
|
||||
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
||||
|
||||
protected override ISkin GetSkin() => null;
|
||||
protected internal override ISkin GetSkin() => null;
|
||||
|
||||
public override Stream GetStream(string storagePath) => null;
|
||||
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Tournament.Components;
|
||||
using osu.Game.Tournament.IPC;
|
||||
using osu.Game.Tournament.Screens.Gameplay;
|
||||
using osu.Game.Tournament.Screens.Gameplay.Components;
|
||||
|
||||
@@ -16,16 +18,26 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
[Cached]
|
||||
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay { Width = 0.5f };
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
[Test]
|
||||
public void TestStartupState([Values] TourneyState state)
|
||||
{
|
||||
Add(new GameplayScreen());
|
||||
Add(chat);
|
||||
AddStep("set state", () => IPCInfo.State.Value = state);
|
||||
createScreen();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStartupStateNoCurrentMatch([Values] TourneyState state)
|
||||
{
|
||||
AddStep("set null current", () => Ladder.CurrentMatch.Value = null);
|
||||
AddStep("set state", () => IPCInfo.State.Value = state);
|
||||
createScreen();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWarmup()
|
||||
{
|
||||
createScreen();
|
||||
|
||||
checkScoreVisibility(false);
|
||||
|
||||
toggleWarmup();
|
||||
@@ -35,6 +47,20 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
checkScoreVisibility(false);
|
||||
}
|
||||
|
||||
private void createScreen()
|
||||
{
|
||||
AddStep("setup screen", () =>
|
||||
{
|
||||
Remove(chat);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new GameplayScreen(),
|
||||
chat,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void checkScoreVisibility(bool visible)
|
||||
=> AddUntilStep($"scores {(visible ? "shown" : "hidden")}",
|
||||
() => this.ChildrenOfType<TeamScore>().All(score => score.Alpha == (visible ? 1 : 0)));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Tournament.Screens.TeamWin;
|
||||
|
||||
@@ -10,19 +10,22 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
public class TestSceneTeamWinScreen : TournamentTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
[Test]
|
||||
public void TestBasic()
|
||||
{
|
||||
var match = Ladder.CurrentMatch.Value;
|
||||
AddStep("set up match", () =>
|
||||
{
|
||||
var match = Ladder.CurrentMatch.Value;
|
||||
|
||||
match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
|
||||
match.Completed.Value = true;
|
||||
match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
|
||||
match.Completed.Value = true;
|
||||
});
|
||||
|
||||
Add(new TeamWinScreen
|
||||
AddStep("create screen", () => Add(new TeamWinScreen
|
||||
{
|
||||
FillMode = FillMode.Fit,
|
||||
FillAspectRatio = 16 / 9f
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace osu.Game.Tournament.Tests
|
||||
{
|
||||
public abstract class TournamentTestScene : OsuTestScene
|
||||
{
|
||||
private TournamentMatch match;
|
||||
|
||||
[Cached]
|
||||
protected LadderInfo Ladder { get; private set; } = new LadderInfo();
|
||||
|
||||
@@ -33,19 +35,23 @@ namespace osu.Game.Tournament.Tests
|
||||
{
|
||||
Ladder.Ruleset.Value ??= rulesetStore.AvailableRulesets.First();
|
||||
|
||||
TournamentMatch match = CreateSampleMatch();
|
||||
match = CreateSampleMatch();
|
||||
|
||||
Ladder.Rounds.Add(match.Round.Value);
|
||||
Ladder.Matches.Add(match);
|
||||
Ladder.Teams.Add(match.Team1.Value);
|
||||
Ladder.Teams.Add(match.Team2.Value);
|
||||
|
||||
Ladder.CurrentMatch.Value = match;
|
||||
|
||||
Ruleset.BindTo(Ladder.Ruleset);
|
||||
Dependencies.CacheAs(new StableInfo(storage));
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public virtual void SetUpSteps()
|
||||
{
|
||||
AddStep("set current match", () => Ladder.CurrentMatch.Value = match);
|
||||
}
|
||||
|
||||
public static TournamentMatch CreateSampleMatch() => new TournamentMatch
|
||||
{
|
||||
Team1 =
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user