mirror of
https://github.com/ppy/osu.git
synced 2025-01-27 16:43:20 +08:00
Merge branch 'master' into multi-queueing-modes
This commit is contained in:
commit
e6deb0c873
@ -14,8 +14,8 @@
|
|||||||
"jb"
|
"jb"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"smoogipoo.nvika": {
|
"nvika": {
|
||||||
"version": "1.0.3",
|
"version": "2.2.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"nvika"
|
"nvika"
|
||||||
]
|
]
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<EmbeddedResource Include="Resources\**\*.*" />
|
<EmbeddedResource Include="Resources\**\*.*" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Code Analysis">
|
<ItemGroup Label="Code Analysis">
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.2" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3" PrivateAssets="All" />
|
||||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1029.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1104.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
@ -20,6 +20,7 @@ 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)]
|
[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 = ".*\\\\.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", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
|
||||||
|
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osr", DataHost = "*", DataMimeType = "*/*")]
|
||||||
[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-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-skin-archive")]
|
||||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")]
|
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
|
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } },
|
||||||
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
{
|
{
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
|
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } },
|
||||||
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
{
|
{
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
|
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } },
|
||||||
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
{
|
{
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
|
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } },
|
||||||
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
[TestCase(6.5867229481955389d, "diffcalc-test")]
|
[TestCase(6.5295339534769958d, "diffcalc-test")]
|
||||||
[TestCase(1.0416315570967911d, "zero-length-sliders")]
|
[TestCase(1.1514260533755143d, "zero-length-sliders")]
|
||||||
public void Test(double expected, string name)
|
public void Test(double expected, string name)
|
||||||
=> base.Test(expected, name);
|
=> base.Test(expected, name);
|
||||||
|
|
||||||
[TestCase(8.2730989071947896d, "diffcalc-test")]
|
[TestCase(9.047752485219954d, "diffcalc-test")]
|
||||||
[TestCase(1.2726413186221039d, "zero-length-sliders")]
|
[TestCase(1.3985711787077566d, "zero-length-sliders")]
|
||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new OsuModDoubleTime());
|
=> Test(expected, name, new OsuModDoubleTime());
|
||||||
|
|
||||||
|
34
osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs
Normal file
34
osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs
Normal file
@ -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 NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneNoSpinnerStacking : TestSceneOsuPlayer
|
||||||
|
{
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 10 },
|
||||||
|
Ruleset = ruleset
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 512; i++)
|
||||||
|
{
|
||||||
|
if (i % 32 < 20)
|
||||||
|
beatmap.HitObjects.Add(new Spinner { Position = new Vector2(256, 192), StartTime = i * 200, EndTime = (i * 200) + 100 });
|
||||||
|
}
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
|
@ -12,20 +12,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
{
|
{
|
||||||
public class OsuDifficultyHitObject : DifficultyHitObject
|
public class OsuDifficultyHitObject : DifficultyHitObject
|
||||||
{
|
{
|
||||||
private const int normalized_radius = 52;
|
private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||||
|
private const int min_delta_time = 25;
|
||||||
|
|
||||||
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Milliseconds elapsed since the start time of the previous <see cref="OsuDifficultyHitObject"/>, with a minimum of 25ms to account for simultaneous <see cref="OsuDifficultyHitObject"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public double StrainTime { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Normalized distance from the end position of the previous <see cref="OsuDifficultyHitObject"/> to the start position of this <see cref="OsuDifficultyHitObject"/>.
|
/// Normalized distance from the end position of the previous <see cref="OsuDifficultyHitObject"/> to the start position of this <see cref="OsuDifficultyHitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double JumpDistance { get; private set; }
|
public double JumpDistance { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum distance from the end position of the previous <see cref="OsuDifficultyHitObject"/> to the start position of this <see cref="OsuDifficultyHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public double MovementDistance { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Normalized distance between the start and end position of the previous <see cref="OsuDifficultyHitObject"/>.
|
/// Normalized distance between the start and end position of the previous <see cref="OsuDifficultyHitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -37,6 +38,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double? Angle { get; private set; }
|
public double? Angle { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Milliseconds elapsed since the end time of the previous <see cref="OsuDifficultyHitObject"/>, with a minimum of 25ms.
|
||||||
|
/// </summary>
|
||||||
|
public double MovementTime { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Milliseconds elapsed since the start time of the previous <see cref="OsuDifficultyHitObject"/> to the end time of the same previous <see cref="OsuDifficultyHitObject"/>, with a minimum of 25ms.
|
||||||
|
/// </summary>
|
||||||
|
public double TravelTime { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Milliseconds elapsed since the start time of the previous <see cref="OsuDifficultyHitObject"/>, with a minimum of 25ms.
|
||||||
|
/// </summary>
|
||||||
|
public readonly double StrainTime;
|
||||||
|
|
||||||
private readonly OsuHitObject lastLastObject;
|
private readonly OsuHitObject lastLastObject;
|
||||||
private readonly OsuHitObject lastObject;
|
private readonly OsuHitObject lastObject;
|
||||||
|
|
||||||
@ -46,13 +62,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
this.lastLastObject = (OsuHitObject)lastLastObject;
|
this.lastLastObject = (OsuHitObject)lastLastObject;
|
||||||
this.lastObject = (OsuHitObject)lastObject;
|
this.lastObject = (OsuHitObject)lastObject;
|
||||||
|
|
||||||
setDistances();
|
// Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects.
|
||||||
|
StrainTime = Math.Max(DeltaTime, min_delta_time);
|
||||||
|
|
||||||
// Capped to 25ms to prevent difficulty calculation breaking from simulatenous objects.
|
setDistances(clockRate);
|
||||||
StrainTime = Math.Max(DeltaTime, 25);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDistances()
|
private void setDistances(double clockRate)
|
||||||
{
|
{
|
||||||
// We don't need to calculate either angle or distance when one of the last->curr objects is a spinner
|
// We don't need to calculate either angle or distance when one of the last->curr objects is a spinner
|
||||||
if (BaseObject is Spinner || lastObject is Spinner)
|
if (BaseObject is Spinner || lastObject is Spinner)
|
||||||
@ -67,15 +83,29 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
scalingFactor *= 1 + smallCircleBonus;
|
scalingFactor *= 1 + smallCircleBonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2 lastCursorPosition = getEndCursorPosition(lastObject);
|
||||||
|
JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
|
||||||
|
|
||||||
if (lastObject is Slider lastSlider)
|
if (lastObject is Slider lastSlider)
|
||||||
{
|
{
|
||||||
computeSliderCursorPosition(lastSlider);
|
computeSliderCursorPosition(lastSlider);
|
||||||
TravelDistance = lastSlider.LazyTravelDistance * scalingFactor;
|
TravelDistance = lastSlider.LazyTravelDistance * scalingFactor;
|
||||||
|
TravelTime = Math.Max(lastSlider.LazyTravelTime / clockRate, min_delta_time);
|
||||||
|
MovementTime = Math.Max(StrainTime - TravelTime, min_delta_time);
|
||||||
|
|
||||||
|
// Jump distance from the slider tail to the next object, as opposed to the lazy position of JumpDistance.
|
||||||
|
float tailJumpDistance = Vector2.Subtract(lastSlider.TailCircle.StackedPosition, BaseObject.StackedPosition).Length * scalingFactor;
|
||||||
|
|
||||||
|
// For hitobjects which continue in the direction of the slider, the player will normally follow through the slider,
|
||||||
|
// such that they're not jumping from the lazy position but rather from very close to (or the end of) the slider.
|
||||||
|
// In such cases, a leniency is applied by also considering the jump distance from the tail of the slider, and taking the minimum jump distance.
|
||||||
|
MovementDistance = Math.Min(JumpDistance, tailJumpDistance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MovementTime = StrainTime;
|
||||||
|
MovementDistance = JumpDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 lastCursorPosition = getEndCursorPosition(lastObject);
|
|
||||||
|
|
||||||
JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
|
|
||||||
|
|
||||||
if (lastLastObject != null && !(lastLastObject is Spinner))
|
if (lastLastObject != null && !(lastLastObject is Spinner))
|
||||||
{
|
{
|
||||||
@ -98,7 +128,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
|
|
||||||
slider.LazyEndPosition = slider.StackedPosition;
|
slider.LazyEndPosition = slider.StackedPosition;
|
||||||
|
|
||||||
float approxFollowCircleRadius = (float)(slider.Radius * 3);
|
float followCircleRadius = (float)(slider.Radius * 2.4);
|
||||||
var computeVertex = new Action<double>(t =>
|
var computeVertex = new Action<double>(t =>
|
||||||
{
|
{
|
||||||
double progress = (t - slider.StartTime) / slider.SpanDuration;
|
double progress = (t - slider.StartTime) / slider.SpanDuration;
|
||||||
@ -111,11 +141,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
var diff = slider.StackedPosition + slider.Path.PositionAt(progress) - slider.LazyEndPosition.Value;
|
var diff = slider.StackedPosition + slider.Path.PositionAt(progress) - slider.LazyEndPosition.Value;
|
||||||
float dist = diff.Length;
|
float dist = diff.Length;
|
||||||
|
|
||||||
if (dist > approxFollowCircleRadius)
|
slider.LazyTravelTime = t - slider.StartTime;
|
||||||
|
|
||||||
|
if (dist > followCircleRadius)
|
||||||
{
|
{
|
||||||
// The cursor would be outside the follow circle, we need to move it
|
// The cursor would be outside the follow circle, we need to move it
|
||||||
diff.Normalize(); // Obtain direction of diff
|
diff.Normalize(); // Obtain direction of diff
|
||||||
dist -= approxFollowCircleRadius;
|
dist -= followCircleRadius;
|
||||||
slider.LazyEndPosition += diff * dist;
|
slider.LazyEndPosition += diff * dist;
|
||||||
slider.LazyTravelDistance += dist;
|
slider.LazyTravelDistance += dist;
|
||||||
}
|
}
|
||||||
|
@ -14,53 +14,96 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Aim : OsuStrainSkill
|
public class Aim : OsuStrainSkill
|
||||||
{
|
{
|
||||||
private const double angle_bonus_begin = Math.PI / 3;
|
|
||||||
private const double timing_threshold = 107;
|
|
||||||
|
|
||||||
public Aim(Mod[] mods)
|
public Aim(Mod[] mods)
|
||||||
: base(mods)
|
: base(mods)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override int HistoryLength => 2;
|
||||||
|
|
||||||
|
private const double wide_angle_multiplier = 1.5;
|
||||||
|
private const double acute_angle_multiplier = 2.0;
|
||||||
|
|
||||||
private double currentStrain = 1;
|
private double currentStrain = 1;
|
||||||
|
|
||||||
private double skillMultiplier => 26.25;
|
private double skillMultiplier => 23.25;
|
||||||
private double strainDecayBase => 0.15;
|
private double strainDecayBase => 0.15;
|
||||||
|
|
||||||
private double strainValueOf(DifficultyHitObject current)
|
private double strainValueOf(DifficultyHitObject current)
|
||||||
{
|
{
|
||||||
if (current.BaseObject is Spinner)
|
if (current.BaseObject is Spinner || Previous.Count <= 1 || Previous[0].BaseObject is Spinner)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var osuCurrent = (OsuDifficultyHitObject)current;
|
var osuCurrObj = (OsuDifficultyHitObject)current;
|
||||||
|
var osuLastObj = (OsuDifficultyHitObject)Previous[0];
|
||||||
|
var osuLastLastObj = (OsuDifficultyHitObject)Previous[1];
|
||||||
|
|
||||||
double aimStrain = 0;
|
// Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle.
|
||||||
|
double currVelocity = osuCurrObj.JumpDistance / osuCurrObj.StrainTime;
|
||||||
|
|
||||||
if (Previous.Count > 0)
|
// But if the last object is a slider, then we extend the travel velocity through the slider into the current object.
|
||||||
|
if (osuLastObj.BaseObject is Slider)
|
||||||
{
|
{
|
||||||
var osuPrevious = (OsuDifficultyHitObject)Previous[0];
|
double movementVelocity = osuCurrObj.MovementDistance / osuCurrObj.MovementTime; // calculate the movement velocity from slider end to current object
|
||||||
|
double travelVelocity = osuCurrObj.TravelDistance / osuCurrObj.TravelTime; // calculate the slider velocity from slider head to slider end.
|
||||||
|
|
||||||
if (osuCurrent.Angle != null && osuCurrent.Angle.Value > angle_bonus_begin)
|
currVelocity = Math.Max(currVelocity, movementVelocity + travelVelocity); // take the larger total combined velocity.
|
||||||
|
}
|
||||||
|
|
||||||
|
// As above, do the same for the previous hitobject.
|
||||||
|
double prevVelocity = osuLastObj.JumpDistance / osuLastObj.StrainTime;
|
||||||
|
|
||||||
|
if (osuLastLastObj.BaseObject is Slider)
|
||||||
|
{
|
||||||
|
double movementVelocity = osuLastObj.MovementDistance / osuLastObj.MovementTime;
|
||||||
|
double travelVelocity = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
||||||
|
|
||||||
|
prevVelocity = Math.Max(prevVelocity, movementVelocity + travelVelocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
double angleBonus = 0;
|
||||||
|
double aimStrain = currVelocity; // Start strain with regular velocity.
|
||||||
|
|
||||||
|
if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same.
|
||||||
|
{
|
||||||
|
if (osuCurrObj.Angle != null && osuLastObj.Angle != null && osuLastLastObj.Angle != null)
|
||||||
{
|
{
|
||||||
const double scale = 90;
|
double currAngle = osuCurrObj.Angle.Value;
|
||||||
|
double lastAngle = osuLastObj.Angle.Value;
|
||||||
|
double lastLastAngle = osuLastLastObj.Angle.Value;
|
||||||
|
|
||||||
double angleBonus = Math.Sqrt(
|
// Rewarding angles, take the smaller velocity as base.
|
||||||
Math.Max(osuPrevious.JumpDistance - scale, 0)
|
angleBonus = Math.Min(currVelocity, prevVelocity);
|
||||||
* Math.Pow(Math.Sin(osuCurrent.Angle.Value - angle_bonus_begin), 2)
|
|
||||||
* Math.Max(osuCurrent.JumpDistance - scale, 0));
|
double wideAngleBonus = calcWideAngleBonus(currAngle);
|
||||||
aimStrain = 1.4 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime);
|
double acuteAngleBonus = calcAcuteAngleBonus(currAngle);
|
||||||
|
|
||||||
|
if (osuCurrObj.StrainTime > 100) // Only buff deltaTime exceeding 300 bpm 1/2.
|
||||||
|
acuteAngleBonus = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
acuteAngleBonus *= calcAcuteAngleBonus(lastAngle) // Multiply by previous angle, we don't want to buff unless this is a wiggle type pattern.
|
||||||
|
* Math.Min(angleBonus, 125 / osuCurrObj.StrainTime) // The maximum velocity we buff is equal to 125 / strainTime
|
||||||
|
* Math.Pow(Math.Sin(Math.PI / 2 * Math.Min(1, (100 - osuCurrObj.StrainTime) / 25)), 2) // scale buff from 150 bpm 1/4 to 200 bpm 1/4
|
||||||
|
* Math.Pow(Math.Sin(Math.PI / 2 * (Math.Clamp(osuCurrObj.JumpDistance, 50, 100) - 50) / 50), 2); // Buff distance exceeding 50 (radius) up to 100 (diameter).
|
||||||
|
}
|
||||||
|
|
||||||
|
wideAngleBonus *= angleBonus * (1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3))); // Penalize wide angles if they're repeated, reducing the penalty as the lastAngle gets more acute.
|
||||||
|
acuteAngleBonus *= 0.5 + 0.5 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastLastAngle), 3))); // Penalize acute angles if they're repeated, reducing the penalty as the lastLastAngle gets more obtuse.
|
||||||
|
|
||||||
|
angleBonus = acuteAngleBonus * acute_angle_multiplier + wideAngleBonus * wide_angle_multiplier; // add the angle buffs together.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double jumpDistanceExp = applyDiminishingExp(osuCurrent.JumpDistance);
|
aimStrain += angleBonus; // Add in angle bonus.
|
||||||
double travelDistanceExp = applyDiminishingExp(osuCurrent.TravelDistance);
|
|
||||||
|
|
||||||
return Math.Max(
|
return aimStrain;
|
||||||
aimStrain + (jumpDistanceExp + travelDistanceExp + Math.Sqrt(travelDistanceExp * jumpDistanceExp)) / Math.Max(osuCurrent.StrainTime, timing_threshold),
|
|
||||||
(Math.Sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / osuCurrent.StrainTime
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double calcWideAngleBonus(double angle) => Math.Pow(Math.Sin(3.0 / 4 * (Math.Min(5.0 / 6 * Math.PI, Math.Max(Math.PI / 6, angle)) - Math.PI / 6)), 2);
|
||||||
|
|
||||||
|
private double calcAcuteAngleBonus(double angle) => 1 - calcWideAngleBonus(angle);
|
||||||
|
|
||||||
private double applyDiminishingExp(double val) => Math.Pow(val, 0.99);
|
private double applyDiminishingExp(double val) => Math.Pow(val, 0.99);
|
||||||
|
|
||||||
private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);
|
private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);
|
||||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
set => StackHeightBindable.Value = value;
|
set => StackHeightBindable.Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
|
public virtual Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
|
||||||
|
|
||||||
public double Radius => OBJECT_RADIUS * Scale;
|
public double Radius => OBJECT_RADIUS * Scale;
|
||||||
|
|
||||||
|
@ -79,6 +79,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal float LazyTravelDistance;
|
internal float LazyTravelDistance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time taken by the cursor upon completion of this <see cref="Slider"/> if it was hit
|
||||||
|
/// with as few movements as possible. This is set and used by difficulty calculation.
|
||||||
|
/// </summary>
|
||||||
|
internal double LazyTravelTime;
|
||||||
|
|
||||||
public IList<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
|
public IList<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
@ -8,6 +8,7 @@ using osu.Game.Rulesets.Judgements;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -31,6 +32,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaximumBonusSpins { get; protected set; } = 1;
|
public int MaximumBonusSpins { get; protected set; } = 1;
|
||||||
|
|
||||||
|
public override Vector2 StackOffset => Vector2.Zero;
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -673,6 +673,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244)));
|
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[1].Type, Is.EqualTo(null));
|
||||||
|
|
||||||
|
// ReSharper disable once HeuristicUnreachableCode
|
||||||
|
// weird one, see https://youtrack.jetbrains.com/issue/RIDER-70159.
|
||||||
Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3)));
|
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[2].Type, Is.EqualTo(PathType.Bezier));
|
||||||
Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15)));
|
Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15)));
|
||||||
|
@ -846,6 +846,42 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: needs to be pulled across to realm implementation when this file is nuked.
|
||||||
|
[Test]
|
||||||
|
public void TestSaveRemovesInvalidCharactersFromPath()
|
||||||
|
{
|
||||||
|
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
|
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
|
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
|
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||||
|
|
||||||
|
var beatmap = working.Beatmap;
|
||||||
|
|
||||||
|
beatmap.BeatmapInfo.Version = "difficulty";
|
||||||
|
beatmap.BeatmapInfo.Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = "Artist/With\\Slashes",
|
||||||
|
Title = "Title",
|
||||||
|
AuthorString = "mapper",
|
||||||
|
};
|
||||||
|
|
||||||
|
manager.Save(beatmap.BeatmapInfo, working.Beatmap);
|
||||||
|
|
||||||
|
Assert.AreEqual("Artist_With_Slashes - Title (mapper) [difficulty].osu", beatmap.BeatmapInfo.Path);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
host.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCreateNewEmptyBeatmap()
|
public void TestCreateNewEmptyBeatmap()
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
public void TestMissing()
|
public void TestMissing()
|
||||||
{
|
{
|
||||||
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||||
beatmap.Metadata.AudioFile = null;
|
beatmap.Metadata.AudioFile = string.Empty;
|
||||||
|
|
||||||
var mock = new Mock<IWorkingBeatmap>();
|
var mock = new Mock<IWorkingBeatmap>();
|
||||||
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
public void TestMissing()
|
public void TestMissing()
|
||||||
{
|
{
|
||||||
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = string.Empty;
|
||||||
var context = getContext(null, System.Array.Empty<byte>());
|
var context = getContext(null, System.Array.Empty<byte>());
|
||||||
|
|
||||||
Assert.That(check.Run(context), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBackgroundNotSet()
|
public void TestBackgroundNotSet()
|
||||||
{
|
{
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = string.Empty;
|
||||||
|
|
||||||
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
var issues = check.Run(context).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
@ -39,8 +39,8 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCheckNullID()
|
public void TestCheckNullID()
|
||||||
{
|
{
|
||||||
var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved };
|
var ourInfo = new BeatmapSetInfo { Hash = "1" };
|
||||||
var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved };
|
var otherInfo = new BeatmapSetInfo { Hash = "2" };
|
||||||
|
|
||||||
Assert.AreNotEqual(ourInfo, otherInfo);
|
Assert.AreNotEqual(ourInfo, otherInfo);
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered)
|
public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered)
|
||||||
{
|
{
|
||||||
var exampleBeatmapInfo = getExampleBeatmap();
|
var exampleBeatmapInfo = getExampleBeatmap();
|
||||||
exampleBeatmapInfo.Metadata.ArtistUnicode = null;
|
exampleBeatmapInfo.Metadata.ArtistUnicode = string.Empty;
|
||||||
|
|
||||||
var criteria = new FilterCriteria
|
var criteria = new FilterCriteria
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@ -67,9 +68,11 @@ namespace osu.Game.Tests.Online
|
|||||||
var deserialised = JsonConvert.DeserializeObject<APIMod>(JsonConvert.SerializeObject(apiMod));
|
var deserialised = JsonConvert.DeserializeObject<APIMod>(JsonConvert.SerializeObject(apiMod));
|
||||||
var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset());
|
var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset());
|
||||||
|
|
||||||
Assert.That(converted?.AdjustPitch.Value, Is.EqualTo(false));
|
Assert.That(converted, Is.Not.Null);
|
||||||
Assert.That(converted?.InitialRate.Value, Is.EqualTo(1.25));
|
|
||||||
Assert.That(converted?.FinalRate.Value, Is.EqualTo(0.25));
|
Assert.That(converted.AdjustPitch.Value, Is.EqualTo(false));
|
||||||
|
Assert.That(converted.InitialRate.Value, Is.EqualTo(1.25));
|
||||||
|
Assert.That(converted.FinalRate.Value, Is.EqualTo(0.25));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -121,11 +124,11 @@ namespace osu.Game.Tests.Online
|
|||||||
new TestModDifficultyAdjust()
|
new TestModDifficultyAdjust()
|
||||||
};
|
};
|
||||||
|
|
||||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new System.NotImplementedException();
|
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException();
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||||
|
|
||||||
public override string Description { get; } = string.Empty;
|
public override string Description { get; } = string.Empty;
|
||||||
public override string ShortName { get; } = string.Empty;
|
public override string ShortName { get; } = string.Empty;
|
||||||
|
@ -38,6 +38,15 @@ namespace osu.Game.Tests.Skins.IO
|
|||||||
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
|
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public Task TestSingleImportMissingSectionHeader() => runSkinTest(async osu =>
|
||||||
|
{
|
||||||
|
var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", includeSectionHeader: false), "skin.osk"));
|
||||||
|
|
||||||
|
// When the import filename doesn't match, it should be appended (and update the skin.ini).
|
||||||
|
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
|
||||||
|
});
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public Task TestSingleImportMatchingFilename() => runSkinTest(async osu =>
|
public Task TestSingleImportMatchingFilename() => runSkinTest(async osu =>
|
||||||
{
|
{
|
||||||
@ -199,21 +208,23 @@ namespace osu.Game.Tests.Skins.IO
|
|||||||
return zipStream;
|
return zipStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini")
|
private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini", bool includeSectionHeader = true)
|
||||||
{
|
{
|
||||||
var zipStream = new MemoryStream();
|
var zipStream = new MemoryStream();
|
||||||
using var zip = ZipArchive.Create();
|
using var zip = ZipArchive.Create();
|
||||||
zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique));
|
zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique, includeSectionHeader));
|
||||||
zip.SaveTo(zipStream);
|
zip.SaveTo(zipStream);
|
||||||
return zipStream;
|
return zipStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true)
|
private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true, bool includeSectionHeader = true)
|
||||||
{
|
{
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
var writer = new StreamWriter(stream);
|
var writer = new StreamWriter(stream);
|
||||||
|
|
||||||
writer.WriteLine("[General]");
|
if (includeSectionHeader)
|
||||||
|
writer.WriteLine("[General]");
|
||||||
|
|
||||||
writer.WriteLine($"Name: {name}");
|
writer.WriteLine($"Name: {name}");
|
||||||
writer.WriteLine($"Author: {author}");
|
writer.WriteLine($"Author: {author}");
|
||||||
|
|
||||||
|
181
osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
Normal file
181
osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Beatmaps
|
||||||
|
{
|
||||||
|
public class TestSceneBeatmapCard : OsuTestScene
|
||||||
|
{
|
||||||
|
private APIBeatmapSet[] testCases;
|
||||||
|
|
||||||
|
#region Test case generation
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
var normal = CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
normal.HasVideo = true;
|
||||||
|
normal.HasStoryboard = true;
|
||||||
|
|
||||||
|
var undownloadable = getUndownloadableBeatmapSet();
|
||||||
|
|
||||||
|
var someDifficulties = getManyDifficultiesBeatmapSet(11);
|
||||||
|
someDifficulties.Title = someDifficulties.TitleUnicode = "some difficulties";
|
||||||
|
someDifficulties.Status = BeatmapSetOnlineStatus.Qualified;
|
||||||
|
|
||||||
|
var manyDifficulties = getManyDifficultiesBeatmapSet(100);
|
||||||
|
manyDifficulties.Status = BeatmapSetOnlineStatus.Pending;
|
||||||
|
|
||||||
|
var explicitMap = CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
explicitMap.HasExplicitContent = true;
|
||||||
|
|
||||||
|
var featuredMap = CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
featuredMap.TrackId = 1;
|
||||||
|
|
||||||
|
var explicitFeaturedMap = CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
explicitFeaturedMap.HasExplicitContent = true;
|
||||||
|
explicitFeaturedMap.TrackId = 2;
|
||||||
|
|
||||||
|
var longName = CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
longName.Title = longName.TitleUnicode = "this track has an incredibly and implausibly long title";
|
||||||
|
longName.Artist = longName.ArtistUnicode = "and this artist! who would have thunk it. it's really such a long name.";
|
||||||
|
longName.HasExplicitContent = true;
|
||||||
|
longName.TrackId = 444;
|
||||||
|
|
||||||
|
testCases = new[]
|
||||||
|
{
|
||||||
|
normal,
|
||||||
|
undownloadable,
|
||||||
|
someDifficulties,
|
||||||
|
manyDifficulties,
|
||||||
|
explicitMap,
|
||||||
|
featuredMap,
|
||||||
|
explicitFeaturedMap,
|
||||||
|
longName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
|
||||||
|
{
|
||||||
|
OnlineID = 123,
|
||||||
|
Title = "undownloadable beatmap",
|
||||||
|
Artist = "test",
|
||||||
|
Source = "more tests",
|
||||||
|
Author = new User
|
||||||
|
{
|
||||||
|
Username = "BanchoBot",
|
||||||
|
Id = 3,
|
||||||
|
},
|
||||||
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
|
{
|
||||||
|
DownloadDisabled = true,
|
||||||
|
},
|
||||||
|
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||||
|
PlayCount = 123,
|
||||||
|
FavouriteCount = 456,
|
||||||
|
BPM = 111,
|
||||||
|
HasVideo = true,
|
||||||
|
HasStoryboard = true,
|
||||||
|
Covers = new BeatmapSetOnlineCovers(),
|
||||||
|
Beatmaps = new[]
|
||||||
|
{
|
||||||
|
new APIBeatmap
|
||||||
|
{
|
||||||
|
RulesetID = Ruleset.Value.OnlineID,
|
||||||
|
DifficultyName = "Test",
|
||||||
|
StarRating = 6.42,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static APIBeatmapSet getManyDifficultiesBeatmapSet(int count)
|
||||||
|
{
|
||||||
|
var beatmaps = new List<APIBeatmap>();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
beatmaps.Add(new APIBeatmap
|
||||||
|
{
|
||||||
|
RulesetID = i % 4,
|
||||||
|
StarRating = 2 + i % 4 * 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new APIBeatmapSet
|
||||||
|
{
|
||||||
|
OnlineID = 1,
|
||||||
|
Title = "many difficulties beatmap",
|
||||||
|
Artist = "test",
|
||||||
|
Author = new User
|
||||||
|
{
|
||||||
|
Username = "BanchoBot",
|
||||||
|
Id = 3,
|
||||||
|
},
|
||||||
|
HasVideo = true,
|
||||||
|
HasStoryboard = true,
|
||||||
|
Covers = new BeatmapSetOnlineCovers(),
|
||||||
|
Beatmaps = beatmaps.ToArray(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Drawable createContent(OverlayColourScheme colourScheme, Func<APIBeatmapSet, Drawable> creationFunc)
|
||||||
|
{
|
||||||
|
var colourProvider = new OverlayColourProvider(colourScheme);
|
||||||
|
|
||||||
|
return new DependencyProvidingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CachedDependencies = new (Type, object)[]
|
||||||
|
{
|
||||||
|
(typeof(OverlayColourProvider), colourProvider)
|
||||||
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Background5
|
||||||
|
},
|
||||||
|
new BasicScrollContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Full,
|
||||||
|
Padding = new MarginPadding(10),
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
ChildrenEnumerable = testCases.Select(creationFunc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTestCase(Func<APIBeatmapSet, Drawable> creationFunc)
|
||||||
|
{
|
||||||
|
foreach (var scheme in Enum.GetValues(typeof(OverlayColourScheme)).Cast<OverlayColourScheme>())
|
||||||
|
AddStep($"set {scheme} scheme", () => Child = createContent(scheme, creationFunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNormal() => createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
|
|||||||
{
|
{
|
||||||
RulesetID = difficulty.rulesetId,
|
RulesetID = difficulty.rulesetId,
|
||||||
StarRating = difficulty.stars
|
StarRating = difficulty.stars
|
||||||
}).ToList()
|
}).ToArray()
|
||||||
};
|
};
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -5,7 +5,10 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
@ -29,6 +32,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
private ComposeBlueprintContainer blueprintContainer
|
private ComposeBlueprintContainer blueprintContainer
|
||||||
=> Editor.ChildrenOfType<ComposeBlueprintContainer>().First();
|
=> Editor.ChildrenOfType<ComposeBlueprintContainer>().First();
|
||||||
|
|
||||||
|
private ContextMenuContainer contextMenuContainer
|
||||||
|
=> Editor.ChildrenOfType<ContextMenuContainer>().First();
|
||||||
|
|
||||||
private void moveMouseToObject(Func<HitObject> targetFunc)
|
private void moveMouseToObject(Func<HitObject> targetFunc)
|
||||||
{
|
{
|
||||||
AddStep("move mouse to object", () =>
|
AddStep("move mouse to object", () =>
|
||||||
@ -42,6 +48,19 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSelectAndShowContextMenu()
|
||||||
|
{
|
||||||
|
var addedObject = new HitCircle { StartTime = 100, Position = new Vector2(100, 100) };
|
||||||
|
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
|
||||||
|
|
||||||
|
moveMouseToObject(() => addedObject);
|
||||||
|
AddStep("right click", () => InputManager.Click(MouseButton.Right));
|
||||||
|
|
||||||
|
AddUntilStep("hitobject selected", () => EditorBeatmap.SelectedHitObjects.Single() == addedObject);
|
||||||
|
AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType<OsuContextMenu>().Single().State == MenuState.Open);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNudgeSelection()
|
public void TestNudgeSelection()
|
||||||
{
|
{
|
||||||
|
@ -23,10 +23,10 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("set metadata", () =>
|
AddStep("set metadata", () =>
|
||||||
{
|
{
|
||||||
editorBeatmap.Metadata.Artist = "Example Artist";
|
editorBeatmap.Metadata.Artist = "Example Artist";
|
||||||
editorBeatmap.Metadata.ArtistUnicode = null;
|
editorBeatmap.Metadata.ArtistUnicode = string.Empty;
|
||||||
|
|
||||||
editorBeatmap.Metadata.Title = "Example Title";
|
editorBeatmap.Metadata.Title = "Example Title";
|
||||||
editorBeatmap.Metadata.TitleUnicode = null;
|
editorBeatmap.Metadata.TitleUnicode = string.Empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
createSection();
|
createSection();
|
||||||
@ -44,10 +44,10 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("set metadata", () =>
|
AddStep("set metadata", () =>
|
||||||
{
|
{
|
||||||
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
|
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
|
||||||
editorBeatmap.Metadata.Artist = null;
|
editorBeatmap.Metadata.Artist = string.Empty;
|
||||||
|
|
||||||
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
|
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
|
||||||
editorBeatmap.Metadata.Title = null;
|
editorBeatmap.Metadata.Title = string.Empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
createSection();
|
createSection();
|
||||||
@ -86,10 +86,10 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("set metadata", () =>
|
AddStep("set metadata", () =>
|
||||||
{
|
{
|
||||||
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
|
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
|
||||||
editorBeatmap.Metadata.Artist = null;
|
editorBeatmap.Metadata.Artist = string.Empty;
|
||||||
|
|
||||||
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
|
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
|
||||||
editorBeatmap.Metadata.Title = null;
|
editorBeatmap.Metadata.Title = string.Empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
createSection();
|
createSection();
|
||||||
|
@ -136,7 +136,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
return new APIScoreInfo
|
return new APIScoreInfo
|
||||||
{
|
{
|
||||||
OnlineID = 2553163309,
|
OnlineID = 2553163309,
|
||||||
OnlineRulesetID = 0,
|
RulesetID = 0,
|
||||||
Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
|
Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
|
||||||
HasReplay = replayAvailable,
|
HasReplay = replayAvailable,
|
||||||
User = new User
|
User = new User
|
||||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo }
|
ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo }
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos)
|
ScreenSpaceToGamefield = pos => recordingManager?.ToLocalSpace(pos) ?? Vector2.Zero,
|
||||||
},
|
},
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
|
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
|
||||||
{
|
{
|
||||||
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
|
GamefieldToScreenSpace = pos => playbackManager?.ToScreenSpace(pos) ?? Vector2.Zero,
|
||||||
},
|
},
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
|
@ -67,6 +67,36 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
createLoungeRoom(new Room
|
createLoungeRoom(new Room
|
||||||
|
{
|
||||||
|
Name = { Value = "Multiplayer room" },
|
||||||
|
Status = { Value = new RoomStatusOpen() },
|
||||||
|
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||||
|
Type = { Value = MatchType.HeadToHead },
|
||||||
|
Playlist =
|
||||||
|
{
|
||||||
|
new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap =
|
||||||
|
{
|
||||||
|
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
StarDifficulty = 2.5,
|
||||||
|
Metadata =
|
||||||
|
{
|
||||||
|
Artist = "very very very very very very very very very long artist",
|
||||||
|
ArtistUnicode = "very very very very very very very very very long artist",
|
||||||
|
Title = "very very very very very very very very very very very long title",
|
||||||
|
TitleUnicode = "very very very very very very very very very very very long title",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.BeatmapInfo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
createLoungeRoom(new Room
|
||||||
{
|
{
|
||||||
Name = { Value = "Playlist room with multiple beatmaps" },
|
Name = { Value = "Playlist room with multiple beatmaps" },
|
||||||
Status = { Value = new RoomStatusPlaying() },
|
Status = { Value = new RoomStatusPlaying() },
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -223,11 +224,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist()
|
public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist()
|
||||||
{
|
{
|
||||||
var byOnlineId = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
var byOnlineId = CreateAPIBeatmap();
|
||||||
byOnlineId.BeatmapSet.OnlineBeatmapSetID = 1337; // Some random ID that does not exist locally.
|
byOnlineId.OnlineID = 1337; // Some random ID that does not exist locally.
|
||||||
|
|
||||||
var byChecksum = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
var byChecksum = CreateAPIBeatmap();
|
||||||
byChecksum.MD5Hash = "1337"; // Some random checksum that does not exist locally.
|
byChecksum.Checksum = "1337"; // Some random checksum that does not exist locally.
|
||||||
|
|
||||||
createPlaylist(byOnlineId, byChecksum);
|
createPlaylist(byOnlineId, byChecksum);
|
||||||
|
|
||||||
@ -237,8 +238,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestExplicitBeatmapItem()
|
public void TestExplicitBeatmapItem()
|
||||||
{
|
{
|
||||||
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
var beatmap = CreateAPIBeatmap();
|
||||||
beatmap.BeatmapSet.OnlineInfo.HasExplicitContent = true;
|
|
||||||
|
Debug.Assert(beatmap.BeatmapSet != null);
|
||||||
|
|
||||||
|
beatmap.BeatmapSet.HasExplicitContent = true;
|
||||||
|
|
||||||
createPlaylist(beatmap);
|
createPlaylist(beatmap);
|
||||||
}
|
}
|
||||||
@ -355,7 +359,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
|
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPlaylist(params BeatmapInfo[] beatmaps)
|
private void createPlaylist(params IBeatmapInfo[] beatmaps)
|
||||||
{
|
{
|
||||||
AddStep("create playlist", () =>
|
AddStep("create playlist", () =>
|
||||||
{
|
{
|
||||||
|
@ -231,6 +231,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
|
||||||
|
AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -290,6 +293,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
||||||
AddUntilStep("wait for join", () => client.Room != null);
|
AddUntilStep("wait for join", () => client.Room != null);
|
||||||
|
|
||||||
|
AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
|
||||||
|
AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -45,11 +45,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAddNullUser()
|
public void TestAddUnresolvedUser()
|
||||||
{
|
{
|
||||||
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
|
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
|
||||||
|
|
||||||
AddStep("add non-resolvable user", () => Client.AddNullUser());
|
AddStep("add non-resolvable user", () => Client.TestAddUnresolvedUser());
|
||||||
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
|
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);
|
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
|
||||||
|
@ -21,15 +21,12 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestUndownloadableWithLink()
|
public void TestUndownloadableWithLink()
|
||||||
{
|
{
|
||||||
AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
|
AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
{
|
{
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
DownloadDisabled = true,
|
||||||
{
|
ExternalLink = @"https://osu.ppy.sh",
|
||||||
DownloadDisabled = true,
|
|
||||||
ExternalLink = @"https://osu.ppy.sh",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,14 +36,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestUndownloadableNoLink()
|
public void TestUndownloadableNoLink()
|
||||||
{
|
{
|
||||||
AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new BeatmapSetInfo
|
AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
{
|
{
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
DownloadDisabled = true,
|
||||||
{
|
|
||||||
DownloadDisabled = true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -56,15 +50,12 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestPartsRemovedWithLink()
|
public void TestPartsRemovedWithLink()
|
||||||
{
|
{
|
||||||
AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
|
AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
{
|
{
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
DownloadDisabled = false,
|
||||||
{
|
ExternalLink = @"https://osu.ppy.sh",
|
||||||
DownloadDisabled = false,
|
|
||||||
ExternalLink = @"https://osu.ppy.sh",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -74,14 +65,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestNormal()
|
public void TestNormal()
|
||||||
{
|
{
|
||||||
AddStep("set normal beatmapset", () => container.BeatmapSet = new BeatmapSetInfo
|
AddStep("set normal beatmapset", () => container.BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
{
|
{
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
DownloadDisabled = false,
|
||||||
{
|
|
||||||
DownloadDisabled = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.BeatmapSet;
|
using osu.Game.Overlays.BeatmapSet;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
namespace osu.Game.Tests.Visual.Online
|
||||||
{
|
{
|
||||||
@ -35,9 +34,9 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
AddStep("load multiple rulesets beatmapset", () =>
|
AddStep("load multiple rulesets beatmapset", () =>
|
||||||
{
|
{
|
||||||
selector.BeatmapSet = new BeatmapSetInfo
|
selector.BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Beatmaps = enabledRulesets.Select(r => new BeatmapInfo { Ruleset = r }).ToList()
|
Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToArray()
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -53,13 +52,13 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
AddStep("load single ruleset beatmapset", () =>
|
AddStep("load single ruleset beatmapset", () =>
|
||||||
{
|
{
|
||||||
selector.BeatmapSet = new BeatmapSetInfo
|
selector.BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Beatmaps = new List<BeatmapInfo>
|
Beatmaps = new[]
|
||||||
{
|
{
|
||||||
new BeatmapInfo
|
new APIBeatmap
|
||||||
{
|
{
|
||||||
Ruleset = enabledRuleset
|
RulesetID = enabledRuleset.OnlineID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -71,10 +70,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestEmptyBeatmapSet()
|
public void TestEmptyBeatmapSet()
|
||||||
{
|
{
|
||||||
AddStep("load empty beatmapset", () => selector.BeatmapSet = new BeatmapSetInfo
|
AddStep("load empty beatmapset", () => selector.BeatmapSet = new APIBeatmapSet());
|
||||||
{
|
|
||||||
Beatmaps = new List<BeatmapInfo>()
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
|
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
|
||||||
AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value));
|
AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value));
|
||||||
|
@ -49,60 +49,48 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
AddStep(@"show first", () =>
|
AddStep(@"show first", () =>
|
||||||
{
|
{
|
||||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
overlay.ShowBeatmapSet(new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1235,
|
OnlineID = 1235,
|
||||||
Metadata = new BeatmapMetadata
|
Title = @"an awesome beatmap",
|
||||||
|
Artist = @"naru narusegawa",
|
||||||
|
Source = @"hinata sou",
|
||||||
|
Tags = @"test tag tag more tag",
|
||||||
|
Author = new User
|
||||||
{
|
{
|
||||||
Title = @"an awesome beatmap",
|
Username = @"BanchoBot",
|
||||||
Artist = @"naru narusegawa",
|
Id = 3,
|
||||||
Source = @"hinata sou",
|
|
||||||
Tags = @"test tag tag more tag",
|
|
||||||
Author = new User
|
|
||||||
{
|
|
||||||
Username = @"BanchoBot",
|
|
||||||
Id = 3,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
OnlineInfo = new APIBeatmapSet
|
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||||
|
PlayCount = 123,
|
||||||
|
FavouriteCount = 456,
|
||||||
|
Submitted = DateTime.Now,
|
||||||
|
Ranked = DateTime.Now,
|
||||||
|
BPM = 111,
|
||||||
|
HasVideo = true,
|
||||||
|
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||||
|
HasStoryboard = true,
|
||||||
|
Covers = new BeatmapSetOnlineCovers(),
|
||||||
|
Beatmaps = new[]
|
||||||
{
|
{
|
||||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
new APIBeatmap
|
||||||
PlayCount = 123,
|
|
||||||
FavouriteCount = 456,
|
|
||||||
Submitted = DateTime.Now,
|
|
||||||
Ranked = DateTime.Now,
|
|
||||||
BPM = 111,
|
|
||||||
HasVideo = true,
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
HasStoryboard = true,
|
|
||||||
Covers = new BeatmapSetOnlineCovers(),
|
|
||||||
},
|
|
||||||
Beatmaps = new List<BeatmapInfo>
|
|
||||||
{
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
{
|
||||||
StarDifficulty = 9.99,
|
StarRating = 9.99,
|
||||||
Version = @"TEST",
|
DifficultyName = @"TEST",
|
||||||
Length = 456000,
|
Length = 456000,
|
||||||
Ruleset = rulesets.GetRuleset(3),
|
RulesetID = 3,
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
CircleSize = 1,
|
||||||
|
DrainRate = 2.3f,
|
||||||
|
OverallDifficulty = 4.5f,
|
||||||
|
ApproachRate = 6,
|
||||||
|
CircleCount = 111,
|
||||||
|
SliderCount = 12,
|
||||||
|
PlayCount = 222,
|
||||||
|
PassCount = 21,
|
||||||
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
CircleSize = 1,
|
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
DrainRate = 2.3f,
|
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
OverallDifficulty = 4.5f,
|
|
||||||
ApproachRate = 6,
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
|
||||||
CircleCount = 111,
|
|
||||||
SliderCount = 12,
|
|
||||||
PlayCount = 222,
|
|
||||||
PassCount = 21,
|
|
||||||
FailTimes = new APIFailTimes
|
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -120,71 +108,15 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
AddStep(@"show undownloadable", () =>
|
AddStep(@"show undownloadable", () =>
|
||||||
{
|
{
|
||||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
var set = getBeatmapSet();
|
||||||
|
|
||||||
|
set.Availability = new BeatmapSetOnlineAvailability
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1234,
|
DownloadDisabled = true,
|
||||||
Metadata = new BeatmapMetadata
|
ExternalLink = "https://osu.ppy.sh",
|
||||||
{
|
};
|
||||||
Title = @"undownloadable beatmap",
|
|
||||||
Artist = @"no one",
|
overlay.ShowBeatmapSet(set);
|
||||||
Source = @"some source",
|
|
||||||
Tags = @"another test tag tag more test tags",
|
|
||||||
Author = new User
|
|
||||||
{
|
|
||||||
Username = @"BanchoBot",
|
|
||||||
Id = 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
|
||||||
{
|
|
||||||
DownloadDisabled = true,
|
|
||||||
ExternalLink = "https://osu.ppy.sh",
|
|
||||||
},
|
|
||||||
Preview = @"https://b.ppy.sh/preview/1234.mp3",
|
|
||||||
PlayCount = 123,
|
|
||||||
FavouriteCount = 456,
|
|
||||||
Submitted = DateTime.Now,
|
|
||||||
Ranked = DateTime.Now,
|
|
||||||
BPM = 111,
|
|
||||||
HasVideo = true,
|
|
||||||
HasStoryboard = true,
|
|
||||||
Covers = new BeatmapSetOnlineCovers(),
|
|
||||||
Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" },
|
|
||||||
Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" },
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
},
|
|
||||||
Beatmaps = new List<BeatmapInfo>
|
|
||||||
{
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
StarDifficulty = 5.67,
|
|
||||||
Version = @"ANOTHER TEST",
|
|
||||||
Length = 123000,
|
|
||||||
Ruleset = rulesets.GetRuleset(1),
|
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
|
||||||
{
|
|
||||||
CircleSize = 9,
|
|
||||||
DrainRate = 8,
|
|
||||||
OverallDifficulty = 7,
|
|
||||||
ApproachRate = 6,
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
|
||||||
CircleCount = 123,
|
|
||||||
SliderCount = 45,
|
|
||||||
PlayCount = 567,
|
|
||||||
PassCount = 89,
|
|
||||||
FailTimes = new APIFailTimes
|
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
downloadAssert(false);
|
downloadAssert(false);
|
||||||
@ -195,48 +127,30 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
AddStep("show multiple rulesets beatmap", () =>
|
AddStep("show multiple rulesets beatmap", () =>
|
||||||
{
|
{
|
||||||
var beatmaps = new List<BeatmapInfo>();
|
var beatmaps = new List<APIBeatmap>();
|
||||||
|
|
||||||
foreach (var ruleset in rulesets.AvailableRulesets.Skip(1))
|
foreach (var ruleset in rulesets.AvailableRulesets.Skip(1))
|
||||||
{
|
{
|
||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new APIBeatmap
|
||||||
{
|
{
|
||||||
Version = ruleset.Name,
|
DifficultyName = ruleset.Name,
|
||||||
Ruleset = ruleset,
|
RulesetID = ruleset.OnlineID,
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
FailTimes = new APIFailTimes
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
{
|
||||||
FailTimes = new APIFailTimes
|
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
{
|
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
},
|
||||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
var set = getBeatmapSet();
|
||||||
{
|
|
||||||
Metadata = new BeatmapMetadata
|
set.Beatmaps = beatmaps.ToArray();
|
||||||
{
|
|
||||||
Title = @"multiple rulesets beatmap",
|
overlay.ShowBeatmapSet(set);
|
||||||
Artist = @"none",
|
|
||||||
Author = new User
|
|
||||||
{
|
|
||||||
Username = "BanchoBot",
|
|
||||||
Id = 3,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Covers = new BeatmapSetOnlineCovers(),
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
},
|
|
||||||
Beatmaps = beatmaps
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.BeatmapInfo.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value)));
|
AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.Beatmap.Ruleset.OnlineID == overlay.Header.RulesetSelector.Current.Value.OnlineID));
|
||||||
AddAssert("left-most beatmap selected", () => overlay.Header.HeaderContent.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
|
AddAssert("left-most beatmap selected", () => overlay.Header.HeaderContent.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +160,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("show explicit map", () =>
|
AddStep("show explicit map", () =>
|
||||||
{
|
{
|
||||||
var beatmapSet = getBeatmapSet();
|
var beatmapSet = getBeatmapSet();
|
||||||
beatmapSet.OnlineInfo.HasExplicitContent = true;
|
beatmapSet.HasExplicitContent = true;
|
||||||
overlay.ShowBeatmapSet(beatmapSet);
|
overlay.ShowBeatmapSet(beatmapSet);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -257,7 +171,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("show featured map", () =>
|
AddStep("show featured map", () =>
|
||||||
{
|
{
|
||||||
var beatmapSet = getBeatmapSet();
|
var beatmapSet = getBeatmapSet();
|
||||||
beatmapSet.OnlineInfo.TrackId = 1;
|
beatmapSet.TrackId = 1;
|
||||||
overlay.ShowBeatmapSet(beatmapSet);
|
overlay.ShowBeatmapSet(beatmapSet);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -274,63 +188,41 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep(@"show without reload", overlay.Show);
|
AddStep(@"show without reload", overlay.Show);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo createManyDifficultiesBeatmapSet()
|
private APIBeatmapSet createManyDifficultiesBeatmapSet()
|
||||||
{
|
{
|
||||||
var beatmaps = new List<BeatmapInfo>();
|
var set = getBeatmapSet();
|
||||||
|
|
||||||
|
var beatmaps = new List<APIBeatmap>();
|
||||||
|
|
||||||
for (int i = 1; i < 41; i++)
|
for (int i = 1; i < 41; i++)
|
||||||
{
|
{
|
||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new APIBeatmap
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = i * 10,
|
OnlineID = i * 10,
|
||||||
Version = $"Test #{i}",
|
DifficultyName = $"Test #{i}",
|
||||||
Ruleset = Ruleset.Value,
|
RulesetID = Ruleset.Value.ID ?? -1,
|
||||||
StarDifficulty = 2 + i * 0.1,
|
StarRating = 2 + i * 0.1,
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
OverallDifficulty = 3.5f,
|
||||||
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
OverallDifficulty = 3.5f,
|
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
|
||||||
|
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
|
||||||
},
|
},
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
|
||||||
FailTimes = new APIFailTimes
|
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BeatmapSetInfo
|
set.Beatmaps = beatmaps.ToArray();
|
||||||
{
|
|
||||||
OnlineBeatmapSetID = 123,
|
return set;
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
|
||||||
Title = @"many difficulties beatmap",
|
|
||||||
Artist = @"none",
|
|
||||||
Author = new User
|
|
||||||
{
|
|
||||||
Username = @"BanchoBot",
|
|
||||||
Id = 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Preview = @"https://b.ppy.sh/preview/123.mp3",
|
|
||||||
HasVideo = true,
|
|
||||||
HasStoryboard = true,
|
|
||||||
Covers = new BeatmapSetOnlineCovers(),
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
},
|
|
||||||
Beatmaps = beatmaps,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo getBeatmapSet()
|
private APIBeatmapSet getBeatmapSet()
|
||||||
{
|
{
|
||||||
var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
var beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
|
||||||
// Make sure the overlay is reloaded (see `BeatmapSetInfo.Equals`).
|
// Make sure the overlay is reloaded (see `BeatmapSetInfo.Equals`).
|
||||||
beatmapSet.OnlineBeatmapSetID = nextBeatmapSetId++;
|
beatmapSet.OnlineID = nextBeatmapSetId++;
|
||||||
|
|
||||||
return beatmapSet;
|
return beatmapSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -44,27 +43,21 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("set second set", () => details.BeatmapSet = secondSet);
|
AddStep("set second set", () => details.BeatmapSet = secondSet);
|
||||||
AddAssert("ratings set", () => details.Ratings.Ratings == secondSet.Ratings);
|
AddAssert("ratings set", () => details.Ratings.Ratings == secondSet.Ratings);
|
||||||
|
|
||||||
static BeatmapSetInfo createSet() => new BeatmapSetInfo
|
static APIBeatmapSet createSet() => new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Beatmaps = new List<BeatmapInfo>
|
Beatmaps = new[]
|
||||||
{
|
{
|
||||||
new BeatmapInfo
|
new APIBeatmap
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmap
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
FailTimes = new APIFailTimes
|
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||||
{
|
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
},
|
||||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OnlineInfo = new APIBeatmapSet
|
Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
|
||||||
{
|
Status = BeatmapSetOnlineStatus.Ranked
|
||||||
Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
|
|
||||||
Status = BeatmapSetOnlineStatus.Ranked
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,21 +59,18 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
var firstBeatmap = createBeatmap();
|
var firstBeatmap = createBeatmap();
|
||||||
var secondBeatmap = createBeatmap();
|
var secondBeatmap = createBeatmap();
|
||||||
|
|
||||||
AddStep("set first set", () => successRate.BeatmapInfo = firstBeatmap);
|
AddStep("set first set", () => successRate.Beatmap = firstBeatmap);
|
||||||
AddAssert("ratings set", () => successRate.Graph.FailTimes == firstBeatmap.FailTimes);
|
AddAssert("ratings set", () => successRate.Graph.FailTimes == firstBeatmap.FailTimes);
|
||||||
|
|
||||||
AddStep("set second set", () => successRate.BeatmapInfo = secondBeatmap);
|
AddStep("set second set", () => successRate.Beatmap = secondBeatmap);
|
||||||
AddAssert("ratings set", () => successRate.Graph.FailTimes == secondBeatmap.FailTimes);
|
AddAssert("ratings set", () => successRate.Graph.FailTimes == secondBeatmap.FailTimes);
|
||||||
|
|
||||||
static BeatmapInfo createBeatmap() => new BeatmapInfo
|
static APIBeatmap createBeatmap() => new APIBeatmap
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmap
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
FailTimes = new APIFailTimes
|
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||||
{
|
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -81,14 +78,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestOnlyFailMetrics()
|
public void TestOnlyFailMetrics()
|
||||||
{
|
{
|
||||||
AddStep("set beatmap", () => successRate.BeatmapInfo = new BeatmapInfo
|
AddStep("set beatmap", () => successRate.Beatmap = new APIBeatmap
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmap
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
FailTimes = new APIFailTimes
|
Fails = Enumerable.Range(1, 100).ToArray(),
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).ToArray(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -98,12 +92,9 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestEmptyMetrics()
|
public void TestEmptyMetrics()
|
||||||
{
|
{
|
||||||
AddStep("set beatmap", () => successRate.BeatmapInfo = new BeatmapInfo
|
AddStep("set beatmap", () => successRate.Beatmap = new APIBeatmap
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmap
|
FailTimes = new APIFailTimes()
|
||||||
{
|
|
||||||
FailTimes = new APIFailTimes(),
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("graph max values correct", () => successRate.ChildrenOfType<BarGraph>().All(graph => graph.MaxValue == 0));
|
AddAssert("graph max values correct", () => successRate.ChildrenOfType<BarGraph>().All(graph => graph.MaxValue == 0));
|
||||||
|
@ -9,7 +9,6 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays.BeatmapListing.Panels;
|
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||||
using osu.Game.Rulesets.Osu;
|
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -69,24 +68,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.DownloadEnabled == enabled);
|
AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.DownloadEnabled == enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo createSoleily()
|
private void createButtonWithBeatmap(IBeatmapSetInfo beatmap)
|
||||||
{
|
|
||||||
return new BeatmapSetInfo
|
|
||||||
{
|
|
||||||
ID = 1,
|
|
||||||
OnlineBeatmapSetID = 241526,
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
|
||||||
{
|
|
||||||
DownloadDisabled = false,
|
|
||||||
ExternalLink = string.Empty,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createButtonWithBeatmap(BeatmapSetInfo beatmap)
|
|
||||||
{
|
{
|
||||||
AddStep("create button", () =>
|
AddStep("create button", () =>
|
||||||
{
|
{
|
||||||
@ -112,32 +94,47 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo getDownloadableBeatmapSet()
|
private IBeatmapSetInfo createSoleily()
|
||||||
{
|
{
|
||||||
var normal = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
|
return new APIBeatmapSet
|
||||||
normal.OnlineInfo.HasVideo = true;
|
{
|
||||||
normal.OnlineInfo.HasStoryboard = true;
|
OnlineID = 241526,
|
||||||
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
return normal;
|
{
|
||||||
|
DownloadDisabled = false,
|
||||||
|
ExternalLink = string.Empty,
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo getUndownloadableBeatmapSet()
|
private IBeatmapSetInfo getDownloadableBeatmapSet()
|
||||||
{
|
{
|
||||||
var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
|
var apiBeatmapSet = CreateAPIBeatmapSet();
|
||||||
beatmap.Metadata.Artist = "test";
|
|
||||||
beatmap.Metadata.Title = "undownloadable";
|
|
||||||
beatmap.Metadata.AuthorString = "test";
|
|
||||||
|
|
||||||
beatmap.OnlineInfo.HasVideo = true;
|
apiBeatmapSet.HasVideo = true;
|
||||||
beatmap.OnlineInfo.HasStoryboard = true;
|
apiBeatmapSet.HasStoryboard = true;
|
||||||
|
|
||||||
beatmap.OnlineInfo.Availability = new BeatmapSetOnlineAvailability
|
return apiBeatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBeatmapSetInfo getUndownloadableBeatmapSet()
|
||||||
|
{
|
||||||
|
var apiBeatmapSet = CreateAPIBeatmapSet();
|
||||||
|
|
||||||
|
apiBeatmapSet.Artist = "test";
|
||||||
|
apiBeatmapSet.Title = "undownloadable";
|
||||||
|
apiBeatmapSet.AuthorString = "test";
|
||||||
|
|
||||||
|
apiBeatmapSet.HasVideo = true;
|
||||||
|
apiBeatmapSet.HasStoryboard = true;
|
||||||
|
|
||||||
|
apiBeatmapSet.Availability = new BeatmapSetOnlineAvailability
|
||||||
{
|
{
|
||||||
DownloadDisabled = true,
|
DownloadDisabled = true,
|
||||||
ExternalLink = "http://osu.ppy.sh",
|
ExternalLink = "http://osu.ppy.sh",
|
||||||
};
|
};
|
||||||
|
|
||||||
return beatmap;
|
return apiBeatmapSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestDownloadButton : BeatmapPanelDownloadButton
|
private class TestDownloadButton : BeatmapPanelDownloadButton
|
||||||
@ -146,7 +143,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
|
|
||||||
public DownloadState DownloadState => State.Value;
|
public DownloadState DownloadState => State.Value;
|
||||||
|
|
||||||
public TestDownloadButton(BeatmapSetInfo beatmapSet)
|
public TestDownloadButton(IBeatmapSetInfo beatmapSet)
|
||||||
: base(beatmapSet)
|
: base(beatmapSet)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -18,104 +18,25 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Cached(typeof(IPreviewTrackOwner))]
|
[Cached(typeof(IPreviewTrackOwner))]
|
||||||
public class TestSceneDirectPanel : OsuTestScene, IPreviewTrackOwner
|
public class TestSceneDirectPanel : OsuTestScene, IPreviewTrackOwner
|
||||||
{
|
{
|
||||||
private BeatmapSetInfo getUndownloadableBeatmapSet() => new BeatmapSetInfo
|
|
||||||
{
|
|
||||||
OnlineBeatmapSetID = 123,
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
|
||||||
Title = "undownloadable beatmap",
|
|
||||||
Artist = "test",
|
|
||||||
Source = "more tests",
|
|
||||||
Author = new User
|
|
||||||
{
|
|
||||||
Username = "BanchoBot",
|
|
||||||
Id = 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Availability = new BeatmapSetOnlineAvailability
|
|
||||||
{
|
|
||||||
DownloadDisabled = true,
|
|
||||||
},
|
|
||||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
|
||||||
PlayCount = 123,
|
|
||||||
FavouriteCount = 456,
|
|
||||||
BPM = 111,
|
|
||||||
HasVideo = true,
|
|
||||||
HasStoryboard = true,
|
|
||||||
Covers = new BeatmapSetOnlineCovers(),
|
|
||||||
},
|
|
||||||
Beatmaps = new List<BeatmapInfo>
|
|
||||||
{
|
|
||||||
new BeatmapInfo
|
|
||||||
{
|
|
||||||
Ruleset = Ruleset.Value,
|
|
||||||
Version = "Test",
|
|
||||||
StarDifficulty = 6.42,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private BeatmapSetInfo getManyDifficultiesBeatmapSet(RulesetStore rulesets)
|
|
||||||
{
|
|
||||||
var beatmaps = new List<BeatmapInfo>();
|
|
||||||
|
|
||||||
for (int i = 0; i < 100; i++)
|
|
||||||
{
|
|
||||||
beatmaps.Add(new BeatmapInfo
|
|
||||||
{
|
|
||||||
Ruleset = rulesets.GetRuleset(i % 4),
|
|
||||||
StarDifficulty = 2 + i % 4 * 2,
|
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
|
||||||
{
|
|
||||||
OverallDifficulty = 3.5f,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BeatmapSetInfo
|
|
||||||
{
|
|
||||||
OnlineBeatmapSetID = 1,
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
|
||||||
Title = "many difficulties beatmap",
|
|
||||||
Artist = "test",
|
|
||||||
Author = new User
|
|
||||||
{
|
|
||||||
Username = "BanchoBot",
|
|
||||||
Id = 3,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
HasVideo = true,
|
|
||||||
HasStoryboard = true,
|
|
||||||
Covers = new BeatmapSetOnlineCovers(),
|
|
||||||
},
|
|
||||||
Beatmaps = beatmaps,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetStore rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
var normal = getBeatmapSet();
|
var normal = getBeatmapSet();
|
||||||
normal.OnlineInfo.HasVideo = true;
|
normal.HasVideo = true;
|
||||||
normal.OnlineInfo.HasStoryboard = true;
|
normal.HasStoryboard = true;
|
||||||
|
|
||||||
var undownloadable = getUndownloadableBeatmapSet();
|
var undownloadable = getUndownloadableBeatmapSet();
|
||||||
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
|
var manyDifficulties = getManyDifficultiesBeatmapSet();
|
||||||
|
|
||||||
var explicitMap = getBeatmapSet();
|
var explicitMap = getBeatmapSet();
|
||||||
explicitMap.OnlineInfo.HasExplicitContent = true;
|
explicitMap.HasExplicitContent = true;
|
||||||
|
|
||||||
var featuredMap = getBeatmapSet();
|
var featuredMap = getBeatmapSet();
|
||||||
featuredMap.OnlineInfo.TrackId = 1;
|
featuredMap.TrackId = 1;
|
||||||
|
|
||||||
var explicitFeaturedMap = getBeatmapSet();
|
var explicitFeaturedMap = getBeatmapSet();
|
||||||
explicitFeaturedMap.OnlineInfo.HasExplicitContent = true;
|
explicitFeaturedMap.HasExplicitContent = true;
|
||||||
explicitFeaturedMap.OnlineInfo.TrackId = 2;
|
explicitFeaturedMap.TrackId = 2;
|
||||||
|
|
||||||
Child = new BasicScrollContainer
|
Child = new BasicScrollContainer
|
||||||
{
|
{
|
||||||
@ -145,7 +66,72 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
BeatmapSetInfo getBeatmapSet() => CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
APIBeatmapSet getBeatmapSet() => CreateAPIBeatmapSet(Ruleset.Value);
|
||||||
|
|
||||||
|
APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
|
||||||
|
{
|
||||||
|
OnlineID = 123,
|
||||||
|
Title = "undownloadable beatmap",
|
||||||
|
Artist = "test",
|
||||||
|
Source = "more tests",
|
||||||
|
Author = new User
|
||||||
|
{
|
||||||
|
Username = "BanchoBot",
|
||||||
|
Id = 3,
|
||||||
|
},
|
||||||
|
Availability = new BeatmapSetOnlineAvailability
|
||||||
|
{
|
||||||
|
DownloadDisabled = true,
|
||||||
|
},
|
||||||
|
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||||
|
PlayCount = 123,
|
||||||
|
FavouriteCount = 456,
|
||||||
|
BPM = 111,
|
||||||
|
HasVideo = true,
|
||||||
|
HasStoryboard = true,
|
||||||
|
Covers = new BeatmapSetOnlineCovers(),
|
||||||
|
Beatmaps = new[]
|
||||||
|
{
|
||||||
|
new APIBeatmap
|
||||||
|
{
|
||||||
|
RulesetID = Ruleset.Value.ID ?? 0,
|
||||||
|
DifficultyName = "Test",
|
||||||
|
StarRating = 6.42,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
APIBeatmapSet getManyDifficultiesBeatmapSet()
|
||||||
|
{
|
||||||
|
var beatmaps = new List<APIBeatmap>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
beatmaps.Add(new APIBeatmap
|
||||||
|
{
|
||||||
|
RulesetID = i % 4,
|
||||||
|
StarRating = 2 + i % 4 * 2,
|
||||||
|
OverallDifficulty = 3.5f,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new APIBeatmapSet
|
||||||
|
{
|
||||||
|
OnlineID = 1,
|
||||||
|
Title = "undownloadable beatmap",
|
||||||
|
Artist = "test",
|
||||||
|
Source = "more tests",
|
||||||
|
Author = new User
|
||||||
|
{
|
||||||
|
Username = "BanchoBot",
|
||||||
|
Id = 3,
|
||||||
|
},
|
||||||
|
HasVideo = true,
|
||||||
|
HasStoryboard = true,
|
||||||
|
Covers = new BeatmapSetOnlineCovers(),
|
||||||
|
Beatmaps = beatmaps.ToArray(),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLoggedOutIn()
|
public void TestLoggedOutIn()
|
||||||
{
|
{
|
||||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet { OnlineID = 88 });
|
||||||
AddStep("log out", () => API.Logout());
|
AddStep("log out", () => API.Logout());
|
||||||
checkEnabled(false);
|
checkEnabled(false);
|
||||||
AddStep("log in", () => API.Login("test", "test"));
|
AddStep("log in", () => API.Login("test", "test"));
|
||||||
@ -40,9 +40,9 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
public void TestBeatmapChange()
|
public void TestBeatmapChange()
|
||||||
{
|
{
|
||||||
AddStep("log in", () => API.Login("test", "test"));
|
AddStep("log in", () => API.Login("test", "test"));
|
||||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet { OnlineID = 88 });
|
||||||
checkEnabled(true);
|
checkEnabled(true);
|
||||||
AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo());
|
AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet());
|
||||||
checkEnabled(false);
|
checkEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
LeaderboardModSelector modSelector;
|
LeaderboardModSelector modSelector;
|
||||||
FillFlowContainer<SpriteText> selectedMods;
|
FillFlowContainer<SpriteText> selectedMods;
|
||||||
var ruleset = new Bindable<RulesetInfo>();
|
|
||||||
|
var ruleset = new Bindable<IRulesetInfo>();
|
||||||
|
|
||||||
Add(selectedMods = new FillFlowContainer<SpriteText>
|
Add(selectedMods = new FillFlowContainer<SpriteText>
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||||
@ -61,10 +62,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModDoubleTime().Acronym,
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
new OsuModHidden().Acronym,
|
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||||
new OsuModFlashlight().Acronym,
|
new APIMod { Acronym = new OsuModFlashlight().Acronym },
|
||||||
new OsuModHardRock().Acronym,
|
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||||
},
|
},
|
||||||
Rank = ScoreRank.XH,
|
Rank = ScoreRank.XH,
|
||||||
PP = 200,
|
PP = 200,
|
||||||
@ -86,9 +87,9 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModDoubleTime().Acronym,
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
new OsuModHidden().Acronym,
|
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||||
new OsuModFlashlight().Acronym,
|
new APIMod { Acronym = new OsuModFlashlight().Acronym },
|
||||||
},
|
},
|
||||||
Rank = ScoreRank.S,
|
Rank = ScoreRank.S,
|
||||||
PP = 190,
|
PP = 190,
|
||||||
@ -110,8 +111,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModDoubleTime().Acronym,
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
new OsuModHidden().Acronym,
|
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||||
},
|
},
|
||||||
Rank = ScoreRank.B,
|
Rank = ScoreRank.B,
|
||||||
PP = 180,
|
PP = 180,
|
||||||
@ -133,7 +134,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModDoubleTime().Acronym,
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
},
|
},
|
||||||
Rank = ScoreRank.C,
|
Rank = ScoreRank.C,
|
||||||
PP = 170,
|
PP = 170,
|
||||||
@ -226,10 +227,10 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
},
|
},
|
||||||
Mods = new[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModDoubleTime().Acronym,
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
new OsuModHidden().Acronym,
|
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||||
new OsuModFlashlight().Acronym,
|
new APIMod { Acronym = new OsuModFlashlight().Acronym },
|
||||||
new OsuModHardRock().Acronym,
|
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||||
},
|
},
|
||||||
Rank = ScoreRank.XH,
|
Rank = ScoreRank.XH,
|
||||||
PP = 200,
|
PP = 200,
|
||||||
|
@ -2,16 +2,16 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Scoring;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osuTK;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
|
||||||
using osu.Game.Overlays;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
namespace osu.Game.Tests.Visual.Online
|
||||||
{
|
{
|
||||||
@ -19,79 +19,79 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
public TestSceneUserProfileScores()
|
public TestSceneUserProfileScores()
|
||||||
{
|
{
|
||||||
var firstScore = new ScoreInfo
|
var firstScore = new APIScoreInfo
|
||||||
{
|
{
|
||||||
PP = 1047.21,
|
PP = 1047.21,
|
||||||
Rank = ScoreRank.SH,
|
Rank = ScoreRank.SH,
|
||||||
BeatmapInfo = new BeatmapInfo
|
Beatmap = new APIBeatmap
|
||||||
{
|
{
|
||||||
Metadata = new BeatmapMetadata
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Title = "JUSTadICE (TV Size)",
|
Title = "JUSTadICE (TV Size)",
|
||||||
Artist = "Oomori Seiko"
|
Artist = "Oomori Seiko",
|
||||||
},
|
},
|
||||||
Version = "Extreme"
|
DifficultyName = "Extreme"
|
||||||
},
|
},
|
||||||
Date = DateTimeOffset.Now,
|
Date = DateTimeOffset.Now,
|
||||||
Mods = new Mod[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModHidden(),
|
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||||
new OsuModHardRock(),
|
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||||
new OsuModDoubleTime()
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
},
|
},
|
||||||
Accuracy = 0.9813
|
Accuracy = 0.9813
|
||||||
};
|
};
|
||||||
|
|
||||||
var secondScore = new ScoreInfo
|
var secondScore = new APIScoreInfo
|
||||||
{
|
{
|
||||||
PP = 134.32,
|
PP = 134.32,
|
||||||
Rank = ScoreRank.A,
|
Rank = ScoreRank.A,
|
||||||
BeatmapInfo = new BeatmapInfo
|
Beatmap = new APIBeatmap
|
||||||
{
|
{
|
||||||
Metadata = new BeatmapMetadata
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Title = "Triumph & Regret",
|
Title = "Triumph & Regret",
|
||||||
Artist = "typeMARS"
|
Artist = "typeMARS",
|
||||||
},
|
},
|
||||||
Version = "[4K] Regret"
|
DifficultyName = "[4K] Regret"
|
||||||
},
|
},
|
||||||
Date = DateTimeOffset.Now,
|
Date = DateTimeOffset.Now,
|
||||||
Mods = new Mod[]
|
Mods = new[]
|
||||||
{
|
{
|
||||||
new OsuModHardRock(),
|
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||||
new OsuModDoubleTime(),
|
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||||
},
|
},
|
||||||
Accuracy = 0.998546
|
Accuracy = 0.998546
|
||||||
};
|
};
|
||||||
|
|
||||||
var thirdScore = new ScoreInfo
|
var thirdScore = new APIScoreInfo
|
||||||
{
|
{
|
||||||
PP = 96.83,
|
PP = 96.83,
|
||||||
Rank = ScoreRank.S,
|
Rank = ScoreRank.S,
|
||||||
BeatmapInfo = new BeatmapInfo
|
Beatmap = new APIBeatmap
|
||||||
{
|
{
|
||||||
Metadata = new BeatmapMetadata
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Title = "Idolize",
|
Title = "Idolize",
|
||||||
Artist = "Creo"
|
Artist = "Creo",
|
||||||
},
|
},
|
||||||
Version = "Insane"
|
DifficultyName = "Insane"
|
||||||
},
|
},
|
||||||
Date = DateTimeOffset.Now,
|
Date = DateTimeOffset.Now,
|
||||||
Accuracy = 0.9726
|
Accuracy = 0.9726
|
||||||
};
|
};
|
||||||
|
|
||||||
var noPPScore = new ScoreInfo
|
var noPPScore = new APIScoreInfo
|
||||||
{
|
{
|
||||||
Rank = ScoreRank.B,
|
Rank = ScoreRank.B,
|
||||||
BeatmapInfo = new BeatmapInfo
|
Beatmap = new APIBeatmap
|
||||||
{
|
{
|
||||||
Metadata = new BeatmapMetadata
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Title = "C18H27NO3(extend)",
|
Title = "C18H27NO3(extend)",
|
||||||
Artist = "Team Grimoire"
|
Artist = "Team Grimoire",
|
||||||
},
|
},
|
||||||
Version = "[4K] Cataclysmic Hypernova"
|
DifficultyName = "[4K] Cataclysmic Hypernova"
|
||||||
},
|
},
|
||||||
Date = DateTimeOffset.Now,
|
Date = DateTimeOffset.Now,
|
||||||
Accuracy = 0.55879
|
Accuracy = 0.55879
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -88,7 +89,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("select EZ mod", () =>
|
AddStep("select EZ mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||||
SelectedMods.Value = new[] { ruleset.CreateMod<ModEasy>() };
|
SelectedMods.Value = new[] { ruleset.CreateMod<ModEasy>() };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,7 +106,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("select HR mod", () =>
|
AddStep("select HR mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||||
SelectedMods.Value = new[] { ruleset.CreateMod<ModHardRock>() };
|
SelectedMods.Value = new[] { ruleset.CreateMod<ModHardRock>() };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -122,9 +123,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("select unchanged Difficulty Adjust mod", () =>
|
AddStep("select unchanged Difficulty Adjust mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||||
var difficultyAdjustMod = ruleset.CreateMod<ModDifficultyAdjust>();
|
var difficultyAdjustMod = ruleset.CreateMod<ModDifficultyAdjust>();
|
||||||
difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.BaseDifficulty);
|
difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.Difficulty);
|
||||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -141,9 +142,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("select changed Difficulty Adjust mod", () =>
|
AddStep("select changed Difficulty Adjust mod", () =>
|
||||||
{
|
{
|
||||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||||
var difficultyAdjustMod = ruleset.CreateMod<OsuModDifficultyAdjust>();
|
var difficultyAdjustMod = ruleset.CreateMod<OsuModDifficultyAdjust>();
|
||||||
var originalDifficulty = advancedStats.BeatmapInfo.BaseDifficulty;
|
var originalDifficulty = advancedStats.BeatmapInfo.Difficulty;
|
||||||
|
|
||||||
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
||||||
difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f;
|
difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f;
|
||||||
|
@ -31,154 +31,112 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestAllMetrics()
|
public void TestAllMetrics()
|
||||||
{
|
{
|
||||||
AddStep("all metrics", () => details.BeatmapInfo = new BeatmapInfo
|
AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap
|
||||||
{
|
{
|
||||||
BeatmapSet = new BeatmapSetInfo
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Version = "All Metrics",
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
{
|
||||||
Source = "osu!",
|
Source = "osu!",
|
||||||
Tags = "this beatmap has all the metrics",
|
Tags = "this beatmap has all the metrics",
|
||||||
|
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||||
},
|
},
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
DifficultyName = "All Metrics",
|
||||||
|
CircleSize = 7,
|
||||||
|
DrainRate = 1,
|
||||||
|
OverallDifficulty = 5.7f,
|
||||||
|
ApproachRate = 3.5f,
|
||||||
|
StarRating = 5.3f,
|
||||||
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
CircleSize = 7,
|
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
DrainRate = 1,
|
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
OverallDifficulty = 5.7f,
|
|
||||||
ApproachRate = 3.5f,
|
|
||||||
},
|
},
|
||||||
StarDifficulty = 5.3f,
|
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
|
||||||
FailTimes = new APIFailTimes
|
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAllMetricsExceptSource()
|
public void TestAllMetricsExceptSource()
|
||||||
{
|
{
|
||||||
AddStep("all except source", () => details.BeatmapInfo = new BeatmapInfo
|
AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap
|
||||||
{
|
{
|
||||||
BeatmapSet = new BeatmapSetInfo
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Version = "All Metrics",
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
{
|
||||||
Tags = "this beatmap has all the metrics",
|
Tags = "this beatmap has all the metrics",
|
||||||
|
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||||
},
|
},
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
DifficultyName = "All Metrics",
|
||||||
|
CircleSize = 7,
|
||||||
|
DrainRate = 1,
|
||||||
|
OverallDifficulty = 5.7f,
|
||||||
|
ApproachRate = 3.5f,
|
||||||
|
StarRating = 5.3f,
|
||||||
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
CircleSize = 7,
|
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
DrainRate = 1,
|
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
OverallDifficulty = 5.7f,
|
|
||||||
ApproachRate = 3.5f,
|
|
||||||
},
|
},
|
||||||
StarDifficulty = 5.3f,
|
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
|
||||||
FailTimes = new APIFailTimes
|
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestOnlyRatings()
|
public void TestOnlyRatings()
|
||||||
{
|
{
|
||||||
AddStep("ratings", () => details.BeatmapInfo = new BeatmapInfo
|
AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap
|
||||||
{
|
{
|
||||||
BeatmapSet = new BeatmapSetInfo
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
|
||||||
OnlineInfo = new APIBeatmapSet
|
|
||||||
{
|
|
||||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Version = "Only Ratings",
|
|
||||||
Metadata = new BeatmapMetadata
|
|
||||||
{
|
{
|
||||||
|
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||||
Source = "osu!",
|
Source = "osu!",
|
||||||
Tags = "this beatmap has ratings metrics but not retries or fails",
|
Tags = "this beatmap has ratings metrics but not retries or fails",
|
||||||
},
|
},
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
DifficultyName = "Only Ratings",
|
||||||
{
|
CircleSize = 6,
|
||||||
CircleSize = 6,
|
DrainRate = 9,
|
||||||
DrainRate = 9,
|
OverallDifficulty = 6,
|
||||||
OverallDifficulty = 6,
|
ApproachRate = 6,
|
||||||
ApproachRate = 6,
|
StarRating = 4.8f,
|
||||||
},
|
|
||||||
StarDifficulty = 4.8f,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestOnlyFailsAndRetries()
|
public void TestOnlyFailsAndRetries()
|
||||||
{
|
{
|
||||||
AddStep("fails retries", () => details.BeatmapInfo = new BeatmapInfo
|
AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap
|
||||||
{
|
{
|
||||||
Version = "Only Retries and Fails",
|
DifficultyName = "Only Retries and Fails",
|
||||||
Metadata = new BeatmapMetadata
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Source = "osu!",
|
Source = "osu!",
|
||||||
Tags = "this beatmap has retries and fails but no ratings",
|
Tags = "this beatmap has retries and fails but no ratings",
|
||||||
},
|
},
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
CircleSize = 3.7f,
|
||||||
|
DrainRate = 6,
|
||||||
|
OverallDifficulty = 6,
|
||||||
|
ApproachRate = 7,
|
||||||
|
StarRating = 2.91f,
|
||||||
|
FailTimes = new APIFailTimes
|
||||||
{
|
{
|
||||||
CircleSize = 3.7f,
|
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
DrainRate = 6,
|
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||||
OverallDifficulty = 6,
|
|
||||||
ApproachRate = 7,
|
|
||||||
},
|
},
|
||||||
StarDifficulty = 2.91f,
|
|
||||||
OnlineInfo = new APIBeatmap
|
|
||||||
{
|
|
||||||
FailTimes = new APIFailTimes
|
|
||||||
{
|
|
||||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNoMetrics()
|
public void TestNoMetrics()
|
||||||
{
|
{
|
||||||
AddStep("no metrics", () => details.BeatmapInfo = new BeatmapInfo
|
AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap
|
||||||
{
|
{
|
||||||
Version = "No Metrics",
|
DifficultyName = "No Metrics",
|
||||||
Metadata = new BeatmapMetadata
|
BeatmapSet = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
Source = "osu!",
|
Source = "osu!",
|
||||||
Tags = "this beatmap has no metrics",
|
Tags = "this beatmap has no metrics",
|
||||||
},
|
},
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
CircleSize = 5,
|
||||||
{
|
DrainRate = 5,
|
||||||
CircleSize = 5,
|
OverallDifficulty = 5.5f,
|
||||||
DrainRate = 5,
|
ApproachRate = 6.5f,
|
||||||
OverallDifficulty = 5.5f,
|
StarRating = 1.97f,
|
||||||
ApproachRate = 6.5f,
|
|
||||||
},
|
|
||||||
StarDifficulty = 1.97f,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,9 +149,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestOnlineMetrics()
|
public void TestOnlineMetrics()
|
||||||
{
|
{
|
||||||
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new BeatmapInfo
|
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap
|
||||||
{
|
{
|
||||||
OnlineBeatmapID = 162,
|
OnlineID = 162,
|
||||||
});
|
});
|
||||||
AddStep("set online", () => api.SetState(APIState.Online));
|
AddStep("set online", () => api.SetState(APIState.Online));
|
||||||
AddStep("set offline", () => api.SetState(APIState.Offline));
|
AddStep("set offline", () => api.SetState(APIState.Offline));
|
||||||
|
@ -110,25 +110,19 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly BeatmapSetInfo beatmap_set = new BeatmapSetInfo
|
private static readonly APIBeatmapSet beatmap_set = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Covers = new BeatmapSetOnlineCovers
|
||||||
{
|
{
|
||||||
Covers = new BeatmapSetOnlineCovers
|
Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305"
|
||||||
{
|
|
||||||
Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly BeatmapSetInfo no_cover_beatmap_set = new BeatmapSetInfo
|
private static readonly APIBeatmapSet no_cover_beatmap_set = new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Covers = new BeatmapSetOnlineCovers
|
||||||
{
|
{
|
||||||
Covers = new BeatmapSetOnlineCovers
|
Cover = string.Empty
|
||||||
{
|
|
||||||
Cover = string.Empty
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -65,10 +66,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private void createPaddedComponent(bool hasDescription = false, bool padded = true)
|
private void createPaddedComponent(bool hasDescription = false, bool padded = true)
|
||||||
{
|
{
|
||||||
|
LabelledDrawable<Drawable> component = null;
|
||||||
|
|
||||||
AddStep("create component", () =>
|
AddStep("create component", () =>
|
||||||
{
|
{
|
||||||
LabelledDrawable<Drawable> component;
|
|
||||||
|
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -81,6 +82,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
component.Label = "a sample component";
|
component.Label = "a sample component";
|
||||||
component.Description = hasDescription ? "this text describes the component" : string.Empty;
|
component.Description = hasDescription ? "this text describes the component" : string.Empty;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddAssert($"description {(hasDescription ? "visible" : "hidden")}", () => component.ChildrenOfType<TextFlowContainer>().ElementAt(1).IsPresent == hasDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PaddedLabelledDrawable : LabelledDrawable<Drawable>
|
private class PaddedLabelledDrawable : LabelledDrawable<Drawable>
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Beatmaps.Drawables;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Tests.Beatmaps.IO;
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -24,7 +25,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private BeatmapSetInfo testBeatmap;
|
private BeatmapSetInfo testBeatmap;
|
||||||
private IAPIProvider api;
|
private IAPIProvider api;
|
||||||
private RulesetStore rulesets;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
@ -33,7 +33,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
|
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.rulesets = rulesets;
|
|
||||||
|
|
||||||
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).Result;
|
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).Result;
|
||||||
}
|
}
|
||||||
@ -81,7 +80,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
Child = background = new TestUpdateableBeatmapBackgroundSprite
|
Child = background = new TestUpdateableBeatmapBackgroundSprite
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Beatmap = { Value = new BeatmapInfo { BeatmapSet = req.Response?.ToBeatmapSet(rulesets) } }
|
Beatmap = { Value = new APIBeatmap { BeatmapSet = req.Response } }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType)
|
AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType)
|
||||||
{
|
{
|
||||||
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
|
OnlineInfo = CreateAPIBeatmapSet(),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
});
|
});
|
||||||
@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("setup covers", () =>
|
AddStep("setup covers", () =>
|
||||||
{
|
{
|
||||||
BeatmapSetInfo setInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
var beatmapSet = CreateAPIBeatmapSet();
|
||||||
|
|
||||||
FillFlowContainer fillFlow;
|
FillFlowContainer fillFlow;
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
var cover = new UpdateableOnlineBeatmapSetCover(coverType)
|
var cover = new UpdateableOnlineBeatmapSetCover(coverType)
|
||||||
{
|
{
|
||||||
OnlineInfo = setInfo.OnlineInfo,
|
OnlineInfo = beatmapSet,
|
||||||
Height = 100,
|
Height = 100,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
};
|
};
|
||||||
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover
|
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover
|
||||||
{
|
{
|
||||||
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
|
OnlineInfo = CreateAPIBeatmapSet(),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
});
|
});
|
||||||
@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover(0)
|
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover(0)
|
||||||
{
|
{
|
||||||
OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg").OnlineInfo,
|
OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg"),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Alpha = 0.4f
|
Alpha = 0.4f
|
||||||
@ -128,16 +128,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1);
|
AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1);
|
||||||
|
|
||||||
AddStep("switch beatmap",
|
AddStep("switch beatmap",
|
||||||
() => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg").OnlineInfo);
|
() => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg"));
|
||||||
AddUntilStep("new cover loaded", () => updateableCover.ChildrenOfType<OnlineBeatmapSetCover>().Except(new[] { initialCover }).Any());
|
AddUntilStep("new cover loaded", () => updateableCover.ChildrenOfType<OnlineBeatmapSetCover>().Except(new[] { initialCover }).Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BeatmapSetInfo createBeatmapWithCover(string coverUrl) => new BeatmapSetInfo
|
private static APIBeatmapSet createBeatmapWithCover(string coverUrl) => new APIBeatmapSet
|
||||||
{
|
{
|
||||||
OnlineInfo = new APIBeatmapSet
|
Covers = new BeatmapSetOnlineCovers { Cover = coverUrl }
|
||||||
{
|
|
||||||
Covers = new BeatmapSetOnlineCovers { Cover = coverUrl }
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover
|
private class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -131,7 +131,7 @@ namespace osu.Game.Beatmaps
|
|||||||
var localRulesetInfo = rulesetInfo as RulesetInfo;
|
var localRulesetInfo = rulesetInfo as RulesetInfo;
|
||||||
|
|
||||||
// Difficulty can only be computed if the beatmap and ruleset are locally available.
|
// Difficulty can only be computed if the beatmap and ruleset are locally available.
|
||||||
if (localBeatmapInfo == null || localRulesetInfo == null)
|
if (localBeatmapInfo == null || localBeatmapInfo.ID == 0 || localRulesetInfo == null)
|
||||||
{
|
{
|
||||||
// If not, fall back to the existing star difficulty (e.g. from an online source).
|
// If not, fall back to the existing star difficulty (e.g. from an online source).
|
||||||
return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
|
return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
[ExcludeFromDynamicCompile]
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IHasPrimaryKey, IBeatmapInfo, IBeatmapOnlineInfo
|
public class BeatmapInfo : IEquatable<BeatmapInfo>, IHasPrimaryKey, IBeatmapInfo
|
||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ namespace osu.Game.Beatmaps
|
|||||||
string IBeatmapInfo.DifficultyName => Version;
|
string IBeatmapInfo.DifficultyName => Version;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata;
|
IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata ?? BeatmapSet?.Metadata ?? new BeatmapMetadata();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => BaseDifficulty;
|
IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => BaseDifficulty;
|
||||||
@ -201,24 +201,5 @@ namespace osu.Game.Beatmaps
|
|||||||
double IBeatmapInfo.StarRating => StarDifficulty;
|
double IBeatmapInfo.StarRating => StarDifficulty;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Implementation of IBeatmapOnlineInfo
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public int CircleCount => OnlineInfo.CircleCount;
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public int SliderCount => OnlineInfo.SliderCount;
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public int PlayCount => OnlineInfo.PlayCount;
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public int PassCount => OnlineInfo.PassCount;
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public APIFailTimes FailTimes => OnlineInfo.FailTimes;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,14 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A user-presentable display title representing this beatmap.
|
/// A user-presentable display title representing this beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo) => $"{getClosestMetadata(beatmapInfo)} {getVersionString(beatmapInfo)}".Trim();
|
public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo) => $"{beatmapInfo.Metadata} {getVersionString(beatmapInfo)}".Trim();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields.
|
/// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true, bool includeCreator = true)
|
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true, bool includeCreator = true)
|
||||||
{
|
{
|
||||||
var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable(includeCreator);
|
var metadata = beatmapInfo.Metadata.GetDisplayTitleRomanisable(includeCreator);
|
||||||
|
|
||||||
if (includeDifficultyName)
|
if (includeDifficultyName)
|
||||||
{
|
{
|
||||||
@ -32,12 +32,8 @@ namespace osu.Game.Beatmaps
|
|||||||
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
|
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
|
||||||
{
|
{
|
||||||
beatmapInfo.DifficultyName
|
beatmapInfo.DifficultyName
|
||||||
}.Concat(getClosestMetadata(beatmapInfo).GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
}.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||||
|
|
||||||
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
||||||
|
|
||||||
// temporary helper methods until we figure which metadata should be where.
|
|
||||||
private static IBeatmapMetadataInfo getClosestMetadata(IBeatmapInfo beatmapInfo) =>
|
|
||||||
beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet?.Metadata ?? new BeatmapMetadata();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,8 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
||||||
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
||||||
/// <param name="beatmapSkin">The beatmap <see cref="ISkin"/> content to write, null if to be omitted.</param>
|
/// <param name="beatmapSkin">The beatmap <see cref="ISkin"/> content to write, null if to be omitted.</param>
|
||||||
public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) => beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
|
public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) =>
|
||||||
|
beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
||||||
@ -249,6 +250,23 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
|
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
|
||||||
|
|
||||||
|
// Temporary method until this class supports IBeatmapSetInfo or otherwise.
|
||||||
|
public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false)
|
||||||
|
{
|
||||||
|
return beatmapModelDownloader.Download(new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
OnlineBeatmapSetID = model.OnlineID,
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Title = model.Metadata?.Title ?? string.Empty,
|
||||||
|
Artist = model.Metadata?.Artist ?? string.Empty,
|
||||||
|
TitleUnicode = model.Metadata?.TitleUnicode ?? string.Empty,
|
||||||
|
ArtistUnicode = model.Metadata?.ArtistUnicode ?? string.Empty,
|
||||||
|
Author = new User { Username = model.Metadata?.Author },
|
||||||
|
}
|
||||||
|
}, minimiseDownloadSize);
|
||||||
|
}
|
||||||
|
|
||||||
public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
|
public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
|
||||||
{
|
{
|
||||||
return beatmapModelDownloader.Download(model, minimiseDownloadSize);
|
return beatmapModelDownloader.Download(model, minimiseDownloadSize);
|
||||||
|
@ -9,6 +9,8 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
[ExcludeFromDynamicCompile]
|
[ExcludeFromDynamicCompile]
|
||||||
@ -17,21 +19,21 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
|
||||||
public string Title { get; set; }
|
public string Title { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonProperty("title_unicode")]
|
[JsonProperty("title_unicode")]
|
||||||
public string TitleUnicode { get; set; }
|
public string TitleUnicode { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Artist { get; set; }
|
public string Artist { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonProperty("artist_unicode")]
|
[JsonProperty("artist_unicode")]
|
||||||
public string ArtistUnicode { get; set; }
|
public string ArtistUnicode { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<BeatmapInfo> Beatmaps { get; set; }
|
public List<BeatmapInfo> Beatmaps { get; set; } = new List<BeatmapInfo>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<BeatmapSetInfo> BeatmapSets { get; set; }
|
public List<BeatmapSetInfo> BeatmapSets { get; set; } = new List<BeatmapSetInfo>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper property to deserialize a username to <see cref="User"/>.
|
/// Helper property to deserialize a username to <see cref="User"/>.
|
||||||
@ -55,7 +57,7 @@ namespace osu.Game.Beatmaps
|
|||||||
[Column("Author")]
|
[Column("Author")]
|
||||||
public string AuthorString
|
public string AuthorString
|
||||||
{
|
{
|
||||||
get => Author?.Username;
|
get => Author?.Username ?? string.Empty;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Author ??= new User();
|
Author ??= new User();
|
||||||
@ -67,22 +69,22 @@ namespace osu.Game.Beatmaps
|
|||||||
/// The author of the beatmaps in this set.
|
/// The author of the beatmaps in this set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public User Author;
|
public User? Author;
|
||||||
|
|
||||||
public string Source { get; set; }
|
public string Source { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonProperty(@"tags")]
|
[JsonProperty(@"tags")]
|
||||||
public string Tags { get; set; }
|
public string Tags { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time in milliseconds to begin playing the track for preview purposes.
|
/// The time in milliseconds to begin playing the track for preview purposes.
|
||||||
/// If -1, the track should begin playing at 40% of its length.
|
/// If -1, the track should begin playing at 40% of its length.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int PreviewTime { get; set; }
|
public int PreviewTime { get; set; } = -1;
|
||||||
|
|
||||||
public string AudioFile { get; set; }
|
public string AudioFile { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string BackgroundFile { get; set; }
|
public string BackgroundFile { get; set; } = string.Empty;
|
||||||
|
|
||||||
public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other);
|
public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other);
|
||||||
|
|
||||||
|
@ -216,7 +216,8 @@ namespace osu.Game.Beatmaps
|
|||||||
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
|
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
|
||||||
|
|
||||||
// metadata may have changed; update the path with the standard format.
|
// metadata may have changed; update the path with the standard format.
|
||||||
beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu";
|
beatmapInfo.Path = GetValidFilename($"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu");
|
||||||
|
|
||||||
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
||||||
|
|
||||||
// update existing or populate new file's filename.
|
// update existing or populate new file's filename.
|
||||||
|
@ -6,10 +6,8 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
@ -32,13 +30,11 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public List<BeatmapInfo> Beatmaps { get; set; }
|
public List<BeatmapInfo> Beatmaps { get; set; }
|
||||||
|
|
||||||
|
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
|
||||||
|
|
||||||
[NotNull]
|
[NotNull]
|
||||||
public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>();
|
public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>();
|
||||||
|
|
||||||
// This field is temporary and only used by `APIBeatmapSet.ToBeatmapSet` (soon to be removed) and tests (to be updated to provide APIBeatmapSet instead).
|
|
||||||
[NotMapped]
|
|
||||||
public APIBeatmapSet OnlineInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum star difficulty of all beatmaps in this set.
|
/// The maximum star difficulty of all beatmaps in this set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -100,80 +96,5 @@ namespace osu.Game.Beatmaps
|
|||||||
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => Files;
|
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => Files;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Delegation for IBeatmapSetOnlineInfo
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public DateTimeOffset Submitted => OnlineInfo.Submitted;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public DateTimeOffset? Ranked => OnlineInfo.Ranked;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public DateTimeOffset? LastUpdated => OnlineInfo.LastUpdated;
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool HasExplicitContent => OnlineInfo.HasExplicitContent;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool HasVideo => OnlineInfo.HasVideo;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool HasStoryboard => OnlineInfo.HasStoryboard;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public BeatmapSetOnlineCovers Covers => OnlineInfo.Covers;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public string Preview => OnlineInfo.Preview;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public double BPM => OnlineInfo.BPM;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public int PlayCount => OnlineInfo.PlayCount;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public int FavouriteCount => OnlineInfo.FavouriteCount;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool HasFavourited => OnlineInfo.HasFavourited;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public BeatmapSetOnlineAvailability Availability => OnlineInfo.Availability;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public BeatmapSetOnlineGenre Genre => OnlineInfo.Genre;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public BeatmapSetOnlineLanguage Language => OnlineInfo.Language;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public int? TrackId => OnlineInfo?.TrackId;
|
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
[JsonIgnore]
|
|
||||||
public int[] Ratings => OnlineInfo?.Ratings;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
280
osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
Normal file
280
osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.BeatmapSet;
|
||||||
|
using osuTK;
|
||||||
|
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.Drawables.Cards
|
||||||
|
{
|
||||||
|
public class BeatmapCard : OsuClickableContainer
|
||||||
|
{
|
||||||
|
public const float TRANSITION_DURATION = 400;
|
||||||
|
|
||||||
|
private const float width = 408;
|
||||||
|
private const float height = 100;
|
||||||
|
private const float corner_radius = 10;
|
||||||
|
|
||||||
|
private readonly APIBeatmapSet beatmapSet;
|
||||||
|
|
||||||
|
private UpdateableOnlineBeatmapSetCover leftCover;
|
||||||
|
private FillFlowContainer iconArea;
|
||||||
|
|
||||||
|
private Container mainContent;
|
||||||
|
private BeatmapCardContentBackground mainContentBackground;
|
||||||
|
|
||||||
|
private GridContainer titleContainer;
|
||||||
|
private GridContainer artistContainer;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; }
|
||||||
|
|
||||||
|
public BeatmapCard(APIBeatmapSet beatmapSet)
|
||||||
|
: base(HoverSampleSet.Submit)
|
||||||
|
{
|
||||||
|
this.beatmapSet = beatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
CornerRadius = corner_radius;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colourProvider.Background3
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = @"Left (icon) area",
|
||||||
|
Size = new Vector2(height),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
leftCover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.List)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
OnlineInfo = beatmapSet
|
||||||
|
},
|
||||||
|
iconArea = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(5),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mainContent = new Container
|
||||||
|
{
|
||||||
|
Name = @"Main content",
|
||||||
|
X = height - corner_radius,
|
||||||
|
Height = height,
|
||||||
|
CornerRadius = corner_radius,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
mainContentBackground = new BeatmapCardContentBackground(beatmapSet)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Horizontal = 10,
|
||||||
|
Vertical = 4
|
||||||
|
},
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
titleContainer = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
ColumnDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.AutoSize)
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize)
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = new RomanisableString(beatmapSet.TitleUnicode, beatmapSet.Title),
|
||||||
|
Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Truncate = true
|
||||||
|
},
|
||||||
|
Empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
artistContainer = new GridContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
ColumnDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.AutoSize)
|
||||||
|
},
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize)
|
||||||
|
},
|
||||||
|
Content = new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = createArtistText(),
|
||||||
|
Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Truncate = true
|
||||||
|
},
|
||||||
|
Empty()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new LinkFlowContainer(s =>
|
||||||
|
{
|
||||||
|
s.Shadow = false;
|
||||||
|
s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
|
||||||
|
}).With(d =>
|
||||||
|
{
|
||||||
|
d.AutoSizeAxes = Axes.Both;
|
||||||
|
d.Margin = new MarginPadding { Top = 2 };
|
||||||
|
d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
|
||||||
|
d.AddUserLink(beatmapSet.Author);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Name = @"Bottom content",
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Horizontal = 10,
|
||||||
|
Vertical = 4
|
||||||
|
},
|
||||||
|
Spacing = new Vector2(4, 0),
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new BeatmapSetOnlineStatusPill
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Status = beatmapSet.Status,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft
|
||||||
|
},
|
||||||
|
new DifficultySpectrumDisplay(beatmapSet)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
DotSize = new Vector2(6, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (beatmapSet.HasVideo)
|
||||||
|
iconArea.Add(new IconPill(FontAwesome.Solid.Film));
|
||||||
|
|
||||||
|
if (beatmapSet.HasStoryboard)
|
||||||
|
iconArea.Add(new IconPill(FontAwesome.Solid.Image));
|
||||||
|
|
||||||
|
if (beatmapSet.HasExplicitContent)
|
||||||
|
{
|
||||||
|
titleContainer.Content[0][1] = new ExplicitContentBeatmapPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
Margin = new MarginPadding { Left = 5 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beatmapSet.TrackId != null)
|
||||||
|
{
|
||||||
|
artistContainer.Content[0][1] = new FeaturedArtistBeatmapPill
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
Margin = new MarginPadding { Left = 5 }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
updateState();
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
updateState();
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
updateState();
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalisableString createArtistText()
|
||||||
|
{
|
||||||
|
var romanisableArtist = new RomanisableString(beatmapSet.ArtistUnicode, beatmapSet.Artist);
|
||||||
|
return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
float targetWidth = width - height;
|
||||||
|
if (IsHovered)
|
||||||
|
targetWidth -= 20;
|
||||||
|
|
||||||
|
mainContent.ResizeWidthTo(targetWidth, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
mainContentBackground.Dimmed.Value = IsHovered;
|
||||||
|
|
||||||
|
leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.Drawables.Cards
|
||||||
|
{
|
||||||
|
public class BeatmapCardContentBackground : CompositeDrawable
|
||||||
|
{
|
||||||
|
public BindableBool Dimmed { get; } = new BindableBool();
|
||||||
|
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly DelayedLoadUnloadWrapper cover;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||||
|
|
||||||
|
public BeatmapCardContentBackground(IBeatmapSetOnlineInfo onlineInfo)
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
cover = new DelayedLoadUnloadWrapper(() => createCover(onlineInfo), 500, 500)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Colour4.Transparent
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Drawable createCover(IBeatmapSetOnlineInfo onlineInfo) => new OnlineBeatmapSetCover(onlineInfo)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
FillMode = FillMode.Fill
|
||||||
|
};
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colourProvider)
|
||||||
|
{
|
||||||
|
background.Colour = colourProvider.Background2;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
Dimmed.BindValueChanged(_ => updateState(), true);
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState() => Schedule(() =>
|
||||||
|
{
|
||||||
|
background.FadeColour(Dimmed.Value ? colourProvider.Background4 : colourProvider.Background2, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
|
||||||
|
var gradient = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0), Colour4.White.Opacity(0.2f));
|
||||||
|
cover.FadeColour(gradient, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -60,8 +60,9 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
/// <param name="ruleset">The ruleset to show the difficulty with.</param>
|
/// <param name="ruleset">The ruleset to show the difficulty with.</param>
|
||||||
/// <param name="mods">The mods to show the difficulty with.</param>
|
/// <param name="mods">The mods to show the difficulty with.</param>
|
||||||
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
|
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
|
||||||
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true)
|
/// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
|
||||||
: this(beatmapInfo, shouldShowTooltip)
|
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
|
||||||
|
: this(beatmapInfo, shouldShowTooltip, performBackgroundDifficultyLookup)
|
||||||
{
|
{
|
||||||
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
|
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
|
||||||
this.mods = mods ?? Array.Empty<Mod>();
|
this.mods = mods ?? Array.Empty<Mod>();
|
||||||
|
@ -57,12 +57,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
return new OnlineBeatmapSetCover(online, beatmapSetCoverType);
|
return new OnlineBeatmapSetCover(online, beatmapSetCoverType);
|
||||||
|
|
||||||
if (model is BeatmapInfo localModel)
|
if (model is BeatmapInfo localModel)
|
||||||
{
|
|
||||||
if (localModel.BeatmapSet?.OnlineInfo != null)
|
|
||||||
return new OnlineBeatmapSetCover(localModel.BeatmapSet.OnlineInfo, beatmapSetCoverType);
|
|
||||||
|
|
||||||
return new BeatmapBackgroundSprite(beatmaps.GetWorkingBeatmap(localModel));
|
return new BeatmapBackgroundSprite(beatmaps.GetWorkingBeatmap(localModel));
|
||||||
}
|
|
||||||
|
|
||||||
return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
|
return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
writer.WriteLine("[General]");
|
writer.WriteLine("[General]");
|
||||||
|
|
||||||
if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
|
if (!string.IsNullOrEmpty(beatmap.Metadata.AudioFile)) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
|
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
|
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
|
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
|
||||||
@ -126,13 +126,13 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
writer.WriteLine("[Metadata]");
|
writer.WriteLine("[Metadata]");
|
||||||
|
|
||||||
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
|
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
|
||||||
if (beatmap.Metadata.TitleUnicode != null) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
|
if (!string.IsNullOrEmpty(beatmap.Metadata.TitleUnicode)) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
|
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
|
||||||
if (beatmap.Metadata.ArtistUnicode != null) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
|
if (!string.IsNullOrEmpty(beatmap.Metadata.ArtistUnicode)) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
|
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
|
||||||
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
|
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
|
||||||
if (beatmap.Metadata.Source != null) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
|
if (!string.IsNullOrEmpty(beatmap.Metadata.Source)) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
|
||||||
if (beatmap.Metadata.Tags != null) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
|
if (!string.IsNullOrEmpty(beatmap.Metadata.Tags)) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
|
||||||
if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
|
if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
|
||||||
if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
|
if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
protected override void ParseStreamInto(LineBufferedReader stream, T output)
|
protected override void ParseStreamInto(LineBufferedReader stream, T output)
|
||||||
{
|
{
|
||||||
Section section = Section.None;
|
Section section = Section.General;
|
||||||
|
|
||||||
string line;
|
string line;
|
||||||
|
|
||||||
@ -47,10 +47,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (line.StartsWith('[') && line.EndsWith(']'))
|
if (line.StartsWith('[') && line.EndsWith(']'))
|
||||||
{
|
{
|
||||||
if (!Enum.TryParse(line[1..^1], out section))
|
if (!Enum.TryParse(line[1..^1], out section))
|
||||||
{
|
|
||||||
Logger.Log($"Unknown section \"{line}\" in \"{output}\"");
|
Logger.Log($"Unknown section \"{line}\" in \"{output}\"");
|
||||||
section = Section.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnBeginNewSection(section);
|
OnBeginNewSection(section);
|
||||||
continue;
|
continue;
|
||||||
@ -148,7 +145,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
protected enum Section
|
protected enum Section
|
||||||
{
|
{
|
||||||
None,
|
|
||||||
General,
|
General,
|
||||||
Editor,
|
Editor,
|
||||||
Metadata,
|
Metadata,
|
||||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The metadata representing this beatmap. May be shared between multiple beatmaps.
|
/// The metadata representing this beatmap. May be shared between multiple beatmaps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IBeatmapMetadataInfo? Metadata { get; }
|
IBeatmapMetadataInfo Metadata { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The difficulty settings for this beatmap.
|
/// The difficulty settings for this beatmap.
|
||||||
|
@ -149,7 +149,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Texture GetBackground()
|
protected override Texture GetBackground()
|
||||||
{
|
{
|
||||||
if (Metadata?.BackgroundFile == null)
|
if (string.IsNullOrEmpty(Metadata?.BackgroundFile))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -165,7 +165,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Track GetBeatmapTrack()
|
protected override Track GetBeatmapTrack()
|
||||||
{
|
{
|
||||||
if (Metadata?.AudioFile == null)
|
if (string.IsNullOrEmpty(Metadata?.AudioFile))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -181,7 +181,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Waveform GetWaveform()
|
protected override Waveform GetWaveform()
|
||||||
{
|
{
|
||||||
if (Metadata?.AudioFile == null)
|
if (string.IsNullOrEmpty(Metadata?.AudioFile))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -466,7 +466,7 @@ namespace osu.Game.Database
|
|||||||
if (retrievedItem == null)
|
if (retrievedItem == null)
|
||||||
throw new ArgumentException(@"Specified model could not be found", nameof(item));
|
throw new ArgumentException(@"Specified model could not be found", nameof(item));
|
||||||
|
|
||||||
string filename = $"{getValidFilename(item.ToString())}{HandledExtensions.First()}";
|
string filename = $"{GetValidFilename(item.ToString())}{HandledExtensions.First()}";
|
||||||
|
|
||||||
using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create))
|
using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create))
|
||||||
ExportModelTo(retrievedItem, stream);
|
ExportModelTo(retrievedItem, stream);
|
||||||
@ -913,9 +913,15 @@ namespace osu.Game.Database
|
|||||||
return Guid.NewGuid().ToString();
|
return Guid.NewGuid().ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getValidFilename(string filename)
|
private readonly char[] invalidFilenameCharacters = Path.GetInvalidFileNameChars()
|
||||||
|
// Backslash is added to avoid issues when exporting to zip.
|
||||||
|
// See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143.
|
||||||
|
.Append('\\')
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
protected string GetValidFilename(string filename)
|
||||||
{
|
{
|
||||||
foreach (char c in Path.GetInvalidFileNameChars())
|
foreach (char c in invalidFilenameCharacters)
|
||||||
filename = filename.Replace(c, '_');
|
filename = filename.Replace(c, '_');
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,10 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
@ -58,23 +56,14 @@ namespace osu.Game.Graphics.Containers
|
|||||||
AddText(text.Substring(previousLinkEnd));
|
AddText(text.Substring(previousLinkEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddLink(string text, string url, Action<SpriteText> creationParameters = null) =>
|
public void AddLink(LocalisableString text, string url, Action<SpriteText> creationParameters = null) =>
|
||||||
createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url);
|
createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url);
|
||||||
|
|
||||||
public void AddLink(string text, Action action, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
public void AddLink(LocalisableString text, Action action, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||||
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action);
|
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action);
|
||||||
|
|
||||||
public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
|
||||||
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
|
|
||||||
|
|
||||||
public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||||
{
|
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
|
||||||
var spriteText = new OsuSpriteText { Text = text };
|
|
||||||
|
|
||||||
AddText(spriteText, creationParameters);
|
|
||||||
RemoveInternal(spriteText); // TODO: temporary, will go away when TextParts support localisation properly.
|
|
||||||
createLink(new TextPartManual(spriteText.Yield()), new LinkDetails(action, argument), tooltipText);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLink(IEnumerable<SpriteText> text, LinkAction action, string linkArgument, string tooltipText = null)
|
public void AddLink(IEnumerable<SpriteText> text, LinkAction action, string linkArgument, string tooltipText = null)
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
@ -19,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool PlaySoundsOnUserChange => true;
|
protected virtual bool PlaySoundsOnUserChange => true;
|
||||||
|
|
||||||
public string LabelText
|
public LocalisableString LabelText
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -156,18 +157,18 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
|||||||
descriptionText.Colour = osuColour.Yellow;
|
descriptionText.Colour = osuColour.Yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Label
|
public LocalisableString Label
|
||||||
{
|
{
|
||||||
set => labelText.Text = value;
|
set => labelText.Text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Description
|
public LocalisableString Description
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
descriptionText.Text = value;
|
descriptionText.Text = value;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrEmpty(value.ToString()))
|
||||||
descriptionText.Show();
|
descriptionText.Show();
|
||||||
else
|
else
|
||||||
descriptionText.Hide();
|
descriptionText.Hide();
|
||||||
|
@ -107,7 +107,8 @@ namespace osu.Game.Online.API
|
|||||||
WebRequest = CreateWebRequest();
|
WebRequest = CreateWebRequest();
|
||||||
WebRequest.Failed += Fail;
|
WebRequest.Failed += Fail;
|
||||||
WebRequest.AllowRetryOnTimeout = false;
|
WebRequest.AllowRetryOnTimeout = false;
|
||||||
WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
|
if (!string.IsNullOrEmpty(API.AccessToken))
|
||||||
|
WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
|
||||||
|
|
||||||
if (isFailing) return;
|
if (isFailing) return;
|
||||||
|
|
||||||
|
@ -14,15 +14,15 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public class GetScoresRequest : APIRequest<APIScoresCollection>
|
public class GetScoresRequest : APIRequest<APIScoresCollection>
|
||||||
{
|
{
|
||||||
private readonly BeatmapInfo beatmapInfo;
|
private readonly IBeatmapInfo beatmapInfo;
|
||||||
private readonly BeatmapLeaderboardScope scope;
|
private readonly BeatmapLeaderboardScope scope;
|
||||||
private readonly RulesetInfo ruleset;
|
private readonly IRulesetInfo ruleset;
|
||||||
private readonly IEnumerable<IMod> mods;
|
private readonly IEnumerable<IMod> mods;
|
||||||
|
|
||||||
public GetScoresRequest(BeatmapInfo beatmapInfo, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod> mods = null)
|
public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod> mods = null)
|
||||||
{
|
{
|
||||||
if (!beatmapInfo.OnlineBeatmapID.HasValue)
|
if (beatmapInfo.OnlineID <= 0)
|
||||||
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
|
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(IBeatmapInfo.OnlineID)}.");
|
||||||
|
|
||||||
if (scope == BeatmapLeaderboardScope.Local)
|
if (scope == BeatmapLeaderboardScope.Local)
|
||||||
throw new InvalidOperationException("Should not attempt to request online scores for a local scoped leaderboard");
|
throw new InvalidOperationException("Should not attempt to request online scores for a local scoped leaderboard");
|
||||||
@ -33,7 +33,7 @@ namespace osu.Game.Online.API.Requests
|
|||||||
this.mods = mods ?? Array.Empty<IMod>();
|
this.mods = mods ?? Array.Empty<IMod>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string Target => $@"beatmaps/{beatmapInfo.OnlineBeatmapID}/scores{createQueryParameters()}";
|
protected override string Target => $@"beatmaps/{beatmapInfo.OnlineID}/scores{createQueryParameters()}";
|
||||||
|
|
||||||
private string createQueryParameters()
|
private string createQueryParameters()
|
||||||
{
|
{
|
||||||
|
@ -43,16 +43,16 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public double StarRating { get; set; }
|
public double StarRating { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"drain")]
|
[JsonProperty(@"drain")]
|
||||||
private float drainRate { get; set; }
|
public float DrainRate { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"cs")]
|
[JsonProperty(@"cs")]
|
||||||
private float circleSize { get; set; }
|
public float CircleSize { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"ar")]
|
[JsonProperty(@"ar")]
|
||||||
private float approachRate { get; set; }
|
public float ApproachRate { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"accuracy")]
|
[JsonProperty(@"accuracy")]
|
||||||
private float overallDifficulty { get; set; }
|
public float OverallDifficulty { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public double Length { get; set; }
|
public double Length { get; set; }
|
||||||
@ -100,10 +100,10 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
MaxCombo = MaxCombo,
|
MaxCombo = MaxCombo,
|
||||||
BaseDifficulty = new BeatmapDifficulty
|
BaseDifficulty = new BeatmapDifficulty
|
||||||
{
|
{
|
||||||
DrainRate = drainRate,
|
DrainRate = DrainRate,
|
||||||
CircleSize = circleSize,
|
CircleSize = CircleSize,
|
||||||
ApproachRate = approachRate,
|
ApproachRate = ApproachRate,
|
||||||
OverallDifficulty = overallDifficulty,
|
OverallDifficulty = OverallDifficulty,
|
||||||
},
|
},
|
||||||
OnlineInfo = this,
|
OnlineInfo = this,
|
||||||
};
|
};
|
||||||
@ -115,10 +115,10 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
|
|
||||||
public IBeatmapDifficultyInfo Difficulty => new BeatmapDifficulty
|
public IBeatmapDifficultyInfo Difficulty => new BeatmapDifficulty
|
||||||
{
|
{
|
||||||
DrainRate = drainRate,
|
DrainRate = DrainRate,
|
||||||
CircleSize = circleSize,
|
CircleSize = CircleSize,
|
||||||
ApproachRate = approachRate,
|
ApproachRate = ApproachRate,
|
||||||
OverallDifficulty = overallDifficulty,
|
OverallDifficulty = OverallDifficulty,
|
||||||
};
|
};
|
||||||
|
|
||||||
IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
|
IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
|
||||||
|
@ -119,7 +119,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public string Tags { get; set; } = string.Empty;
|
public string Tags { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonProperty(@"beatmaps")]
|
[JsonProperty(@"beatmaps")]
|
||||||
public IEnumerable<APIBeatmap> Beatmaps { get; set; } = Array.Empty<APIBeatmap>();
|
public APIBeatmap[] Beatmaps { get; set; } = Array.Empty<APIBeatmap>();
|
||||||
|
|
||||||
public virtual BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
public virtual BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
@ -128,7 +128,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
OnlineBeatmapSetID = OnlineID,
|
OnlineBeatmapSetID = OnlineID,
|
||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
Status = Status,
|
Status = Status,
|
||||||
OnlineInfo = this
|
|
||||||
};
|
};
|
||||||
|
|
||||||
beatmapSet.Beatmaps = Beatmaps.Select(b =>
|
beatmapSet.Beatmaps = Beatmaps.Select(b =>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -36,6 +37,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public DateTimeOffset Date { get; set; }
|
public DateTimeOffset Date { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"beatmap")]
|
[JsonProperty(@"beatmap")]
|
||||||
|
[CanBeNull]
|
||||||
public APIBeatmap Beatmap { get; set; }
|
public APIBeatmap Beatmap { get; set; }
|
||||||
|
|
||||||
[JsonProperty("accuracy")]
|
[JsonProperty("accuracy")]
|
||||||
@ -45,6 +47,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public double? PP { get; set; }
|
public double? PP { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"beatmapset")]
|
[JsonProperty(@"beatmapset")]
|
||||||
|
[CanBeNull]
|
||||||
public APIBeatmapSet BeatmapSet
|
public APIBeatmapSet BeatmapSet
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
@ -62,10 +65,13 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public Dictionary<string, int> Statistics { get; set; }
|
public Dictionary<string, int> Statistics { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"mode_int")]
|
[JsonProperty(@"mode_int")]
|
||||||
public int OnlineRulesetID { get; set; }
|
public int RulesetID { get; set; }
|
||||||
|
|
||||||
[JsonProperty(@"mods")]
|
[JsonProperty(@"mods")]
|
||||||
public string[] Mods { get; set; }
|
private string[] mods { set => Mods = value.Select(acronym => new APIMod { Acronym = acronym }); }
|
||||||
|
|
||||||
|
[NotNull]
|
||||||
|
public IEnumerable<APIMod> Mods { get; set; } = Array.Empty<APIMod>();
|
||||||
|
|
||||||
[JsonProperty("rank")]
|
[JsonProperty("rank")]
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
@ -79,30 +85,30 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
|
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
|
||||||
{
|
{
|
||||||
var ruleset = rulesets.GetRuleset(OnlineRulesetID);
|
var ruleset = rulesets.GetRuleset(RulesetID);
|
||||||
|
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
|
||||||
var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.CreateModFromAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty<Mod>();
|
var modInstances = Mods.Select(apiMod => rulesetInstance.CreateModFromAcronym(apiMod.Acronym)).Where(m => m != null).ToArray();
|
||||||
|
|
||||||
// all API scores provided by this class are considered to be legacy.
|
// all API scores provided by this class are considered to be legacy.
|
||||||
mods = mods.Append(rulesetInstance.CreateMod<ModClassic>()).ToArray();
|
modInstances = modInstances.Append(rulesetInstance.CreateMod<ModClassic>()).ToArray();
|
||||||
|
|
||||||
var scoreInfo = new ScoreInfo
|
var scoreInfo = new ScoreInfo
|
||||||
{
|
{
|
||||||
TotalScore = TotalScore,
|
TotalScore = TotalScore,
|
||||||
MaxCombo = MaxCombo,
|
MaxCombo = MaxCombo,
|
||||||
BeatmapInfo = Beatmap.ToBeatmapInfo(rulesets),
|
BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets),
|
||||||
User = User,
|
User = User,
|
||||||
Accuracy = Accuracy,
|
Accuracy = Accuracy,
|
||||||
OnlineScoreID = OnlineID,
|
OnlineScoreID = OnlineID,
|
||||||
Date = Date,
|
Date = Date,
|
||||||
PP = PP,
|
PP = PP,
|
||||||
RulesetID = OnlineRulesetID,
|
RulesetID = RulesetID,
|
||||||
Hash = HasReplay ? "online" : string.Empty, // todo: temporary?
|
Hash = HasReplay ? "online" : string.Empty, // todo: temporary?
|
||||||
Rank = Rank,
|
Rank = Rank,
|
||||||
Ruleset = ruleset,
|
Ruleset = ruleset,
|
||||||
Mods = mods,
|
Mods = modInstances,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (beatmap != null)
|
if (beatmap != null)
|
||||||
@ -144,7 +150,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
return scoreInfo;
|
return scoreInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRulesetInfo Ruleset => new RulesetInfo { ID = OnlineRulesetID };
|
public IRulesetInfo Ruleset => new RulesetInfo { ID = RulesetID };
|
||||||
|
|
||||||
IBeatmapInfo IScoreInfo.Beatmap => Beatmap;
|
IBeatmapInfo IScoreInfo.Beatmap => Beatmap;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Multiplayer.Queueing;
|
using osu.Game.Online.Multiplayer.Queueing;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Online.Rooms.RoomStatuses;
|
using osu.Game.Online.Rooms.RoomStatuses;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -148,6 +149,10 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
{
|
{
|
||||||
Room = joinedRoom;
|
Room = joinedRoom;
|
||||||
APIRoom = room;
|
APIRoom = room;
|
||||||
|
|
||||||
|
Debug.Assert(LocalUser != null);
|
||||||
|
addUserToAPIRoom(LocalUser);
|
||||||
|
|
||||||
foreach (var user in joinedRoom.Users)
|
foreach (var user in joinedRoom.Users)
|
||||||
updateUserPlayingState(user.UserID, user.State);
|
updateUserPlayingState(user.UserID, user.State);
|
||||||
|
|
||||||
@ -358,6 +363,8 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
|
|
||||||
Room.Users.Add(user);
|
Room.Users.Add(user);
|
||||||
|
|
||||||
|
addUserToAPIRoom(user);
|
||||||
|
|
||||||
UserJoined?.Invoke(user);
|
UserJoined?.Invoke(user);
|
||||||
RoomUpdated?.Invoke();
|
RoomUpdated?.Invoke();
|
||||||
});
|
});
|
||||||
@ -377,6 +384,18 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
return handleUserLeft(user, UserKicked);
|
return handleUserLeft(user, UserKicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addUserToAPIRoom(MultiplayerRoomUser user)
|
||||||
|
{
|
||||||
|
Debug.Assert(APIRoom != null);
|
||||||
|
|
||||||
|
APIRoom.RecentParticipants.Add(user.User ?? new User
|
||||||
|
{
|
||||||
|
Id = user.UserID,
|
||||||
|
Username = "[Unresolved]"
|
||||||
|
});
|
||||||
|
APIRoom.ParticipantCount.Value++;
|
||||||
|
}
|
||||||
|
|
||||||
private Task handleUserLeft(MultiplayerRoomUser user, Action<MultiplayerRoomUser>? callback)
|
private Task handleUserLeft(MultiplayerRoomUser user, Action<MultiplayerRoomUser>? callback)
|
||||||
{
|
{
|
||||||
if (Room == null)
|
if (Room == null)
|
||||||
@ -390,6 +409,10 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
Room.Users.Remove(user);
|
Room.Users.Remove(user);
|
||||||
PlayingUserIds.Remove(user.UserID);
|
PlayingUserIds.Remove(user.UserID);
|
||||||
|
|
||||||
|
Debug.Assert(APIRoom != null);
|
||||||
|
APIRoom.RecentParticipants.RemoveAll(u => u.Id == user.UserID);
|
||||||
|
APIRoom.ParticipantCount.Value--;
|
||||||
|
|
||||||
callback?.Invoke(user);
|
callback?.Invoke(user);
|
||||||
RoomUpdated?.Invoke();
|
RoomUpdated?.Invoke();
|
||||||
}, false);
|
}, false);
|
||||||
@ -667,20 +690,17 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId);
|
CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId);
|
||||||
}, cancellationToken);
|
}, cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves a <see cref="BeatmapSetInfo"/> from an online source.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="beatmapId">The beatmap set ID.</param>
|
|
||||||
/// <param name="cancellationToken">A token to cancel the request.</param>
|
|
||||||
/// <returns>The <see cref="BeatmapSetInfo"/> retrieval task.</returns>
|
|
||||||
protected abstract Task<BeatmapSetInfo> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
private async Task<PlaylistItem> createPlaylistItem(APIPlaylistItem item)
|
private async Task<PlaylistItem> createPlaylistItem(APIPlaylistItem item)
|
||||||
{
|
{
|
||||||
var set = await GetOnlineBeatmapSet(item.BeatmapID).ConfigureAwait(false);
|
var set = await GetOnlineBeatmapSet(item.BeatmapID).ConfigureAwait(false);
|
||||||
|
|
||||||
var beatmap = set.Beatmaps.Single(b => b.OnlineBeatmapID == item.BeatmapID);
|
// The incoming response is deserialised without circular reference handling currently.
|
||||||
beatmap.MD5Hash = item.BeatmapChecksum;
|
// Because we require using metadata from this instance, populate the nested beatmaps' sets manually here.
|
||||||
|
foreach (var b in set.Beatmaps)
|
||||||
|
b.BeatmapSet = set;
|
||||||
|
|
||||||
|
var beatmap = set.Beatmaps.Single(b => b.OnlineID == item.BeatmapID);
|
||||||
|
beatmap.Checksum = item.BeatmapChecksum;
|
||||||
|
|
||||||
var ruleset = Rulesets.GetRuleset(item.RulesetID);
|
var ruleset = Rulesets.GetRuleset(item.RulesetID);
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
@ -699,6 +719,14 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a <see cref="APIBeatmapSet"/> from an online source.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapId">The beatmap set ID.</param>
|
||||||
|
/// <param name="cancellationToken">A token to cancel the request.</param>
|
||||||
|
/// <returns>The <see cref="APIBeatmapSet"/> retrieval task.</returns>
|
||||||
|
protected abstract Task<APIBeatmapSet> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For the provided user ID, update whether the user is included in <see cref="CurrentMatchPlayingUserIds"/>.
|
/// For the provided user ID, update whether the user is included in <see cref="CurrentMatchPlayingUserIds"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,9 +9,9 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
|
||||||
namespace osu.Game.Online.Multiplayer
|
namespace osu.Game.Online.Multiplayer
|
||||||
@ -167,9 +167,9 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), item);
|
return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), item);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task<BeatmapSetInfo> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
|
protected override Task<APIBeatmapSet> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var tcs = new TaskCompletionSource<BeatmapSetInfo>();
|
var tcs = new TaskCompletionSource<APIBeatmapSet>();
|
||||||
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
|
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
|
||||||
|
|
||||||
req.Success += res =>
|
req.Success += res =>
|
||||||
@ -180,7 +180,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcs.SetResult(res.ToBeatmapSet(Rulesets));
|
tcs.SetResult(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
req.Failure += e => tcs.SetException(e);
|
req.Failure += e => tcs.SetException(e);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ namespace osu.Game.Online.Placeholders
|
|||||||
{
|
{
|
||||||
public Action Action;
|
public Action Action;
|
||||||
|
|
||||||
public ClickablePlaceholder(string actionMessage, IconUsage icon)
|
public ClickablePlaceholder(LocalisableString actionMessage, IconUsage icon)
|
||||||
{
|
{
|
||||||
OsuTextFlowContainer textFlow;
|
OsuTextFlowContainer textFlow;
|
||||||
|
|
||||||
|
@ -3,14 +3,15 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Online.Placeholders
|
namespace osu.Game.Online.Placeholders
|
||||||
{
|
{
|
||||||
public class MessagePlaceholder : Placeholder
|
public class MessagePlaceholder : Placeholder
|
||||||
{
|
{
|
||||||
private readonly string message;
|
private readonly LocalisableString message;
|
||||||
|
|
||||||
public MessagePlaceholder(string message)
|
public MessagePlaceholder(LocalisableString message)
|
||||||
{
|
{
|
||||||
AddIcon(FontAwesome.Solid.ExclamationCircle, cp =>
|
AddIcon(FontAwesome.Solid.ExclamationCircle, cp =>
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -61,7 +62,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public MultiplayerScoresAround ScoresAround { get; set; }
|
public MultiplayerScoresAround ScoresAround { get; set; }
|
||||||
|
|
||||||
public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem)
|
public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap)
|
||||||
{
|
{
|
||||||
var rulesetInstance = playlistItem.Ruleset.Value.CreateInstance();
|
var rulesetInstance = playlistItem.Ruleset.Value.CreateInstance();
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
OnlineScoreID = ID,
|
OnlineScoreID = ID,
|
||||||
TotalScore = TotalScore,
|
TotalScore = TotalScore,
|
||||||
MaxCombo = MaxCombo,
|
MaxCombo = MaxCombo,
|
||||||
BeatmapInfo = playlistItem.Beatmap.Value,
|
BeatmapInfo = beatmap,
|
||||||
BeatmapInfoID = playlistItem.BeatmapID,
|
BeatmapInfoID = playlistItem.BeatmapID,
|
||||||
Ruleset = playlistItem.Ruleset.Value,
|
Ruleset = playlistItem.Ruleset.Value,
|
||||||
RulesetID = playlistItem.RulesetID,
|
RulesetID = playlistItem.RulesetID,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -52,8 +53,13 @@ namespace osu.Game.Online.Rooms
|
|||||||
|
|
||||||
downloadTracker?.RemoveAndDisposeImmediately();
|
downloadTracker?.RemoveAndDisposeImmediately();
|
||||||
|
|
||||||
|
Debug.Assert(item.NewValue.Beatmap.Value.BeatmapSet != null);
|
||||||
|
|
||||||
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
|
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
|
||||||
downloadTracker.State.BindValueChanged(_ => updateAvailability());
|
|
||||||
|
AddInternal(downloadTracker);
|
||||||
|
|
||||||
|
downloadTracker.State.BindValueChanged(_ => updateAvailability(), true);
|
||||||
downloadTracker.Progress.BindValueChanged(_ =>
|
downloadTracker.Progress.BindValueChanged(_ =>
|
||||||
{
|
{
|
||||||
if (downloadTracker.State.Value != DownloadState.Downloading)
|
if (downloadTracker.State.Value != DownloadState.Downloading)
|
||||||
@ -63,9 +69,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
// we don't want to flood the network with this, so rate limit how often we send progress updates.
|
// we don't want to flood the network with this, so rate limit how often we send progress updates.
|
||||||
if (progressUpdate?.Completed != false)
|
if (progressUpdate?.Completed != false)
|
||||||
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
||||||
});
|
}, true);
|
||||||
|
|
||||||
AddInternal(downloadTracker);
|
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
public bool Expired { get; set; }
|
public bool Expired { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
|
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
@ -65,13 +65,13 @@ namespace osu.Game.Online.Rooms
|
|||||||
|
|
||||||
public PlaylistItem()
|
public PlaylistItem()
|
||||||
{
|
{
|
||||||
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineBeatmapID ?? 0);
|
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineID ?? -1);
|
||||||
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
|
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets)
|
public void MapObjects(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
Beatmap.Value ??= apiBeatmap.ToBeatmapInfo(rulesets);
|
Beatmap.Value ??= apiBeatmap;
|
||||||
Ruleset.Value ??= rulesets.GetRuleset(RulesetID);
|
Ruleset.Value ??= rulesets.GetRuleset(RulesetID);
|
||||||
|
|
||||||
Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
|
Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
|
||||||
|
@ -5,6 +5,7 @@ using System.Net.Http;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Solo;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Online.Rooms
|
namespace osu.Game.Online.Rooms
|
||||||
@ -14,14 +15,14 @@ namespace osu.Game.Online.Rooms
|
|||||||
private readonly long scoreId;
|
private readonly long scoreId;
|
||||||
private readonly long roomId;
|
private readonly long roomId;
|
||||||
private readonly long playlistItemId;
|
private readonly long playlistItemId;
|
||||||
private readonly ScoreInfo scoreInfo;
|
private readonly SubmittableScore score;
|
||||||
|
|
||||||
public SubmitRoomScoreRequest(long scoreId, long roomId, long playlistItemId, ScoreInfo scoreInfo)
|
public SubmitRoomScoreRequest(long scoreId, long roomId, long playlistItemId, ScoreInfo scoreInfo)
|
||||||
{
|
{
|
||||||
this.scoreId = scoreId;
|
this.scoreId = scoreId;
|
||||||
this.roomId = roomId;
|
this.roomId = roomId;
|
||||||
this.playlistItemId = playlistItemId;
|
this.playlistItemId = playlistItemId;
|
||||||
this.scoreInfo = scoreInfo;
|
score = new SubmittableScore(scoreInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
@ -31,7 +32,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
req.ContentType = "application/json";
|
req.ContentType = "application/json";
|
||||||
req.Method = HttpMethod.Put;
|
req.Method = HttpMethod.Put;
|
||||||
|
|
||||||
req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings
|
req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||||
}));
|
}));
|
||||||
|
@ -35,7 +35,11 @@ namespace osu.Game.Online
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
||||||
var scoreInfo = new ScoreInfo { OnlineScoreID = TrackedItem.OnlineScoreID };
|
var scoreInfo = new ScoreInfo
|
||||||
|
{
|
||||||
|
ID = TrackedItem.ID,
|
||||||
|
OnlineScoreID = TrackedItem.OnlineScoreID
|
||||||
|
};
|
||||||
|
|
||||||
if (Manager.IsAvailableLocally(scoreInfo))
|
if (Manager.IsAvailableLocally(scoreInfo))
|
||||||
UpdateState(DownloadState.LocallyAvailable);
|
UpdateState(DownloadState.LocallyAvailable);
|
||||||
|
@ -436,11 +436,15 @@ namespace osu.Game
|
|||||||
/// <item>first beatmap from any ruleset.</item>
|
/// <item>first beatmap from any ruleset.</item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate<BeatmapInfo> difficultyCriteria = null)
|
public void PresentBeatmap(IBeatmapSetInfo beatmap, Predicate<BeatmapInfo> difficultyCriteria = null)
|
||||||
{
|
{
|
||||||
var databasedSet = beatmap.OnlineBeatmapSetID != null
|
BeatmapSetInfo databasedSet = null;
|
||||||
? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID)
|
|
||||||
: BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash);
|
if (beatmap.OnlineID > 0)
|
||||||
|
databasedSet = BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineID);
|
||||||
|
|
||||||
|
if (beatmap is BeatmapSetInfo localBeatmap)
|
||||||
|
databasedSet ??= BeatmapManager.QueryBeatmapSet(s => s.Hash == localBeatmap.Hash);
|
||||||
|
|
||||||
if (databasedSet == null)
|
if (databasedSet == null)
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@ -135,7 +134,16 @@ namespace osu.Game.Overlays.AccountCreation
|
|||||||
characterCheckText = passwordDescription.AddText("8 characters long");
|
characterCheckText = passwordDescription.AddText("8 characters long");
|
||||||
passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song.");
|
passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song.");
|
||||||
|
|
||||||
passwordTextBox.Current.ValueChanged += password => { characterCheckText.Drawables.ForEach(s => s.Colour = password.NewValue.Length == 0 ? Color4.White : Interpolation.ValueAt(password.NewValue.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); };
|
passwordTextBox.Current.BindValueChanged(_ => updateCharacterCheckTextColour(), true);
|
||||||
|
characterCheckText.DrawablePartsRecreated += _ => updateCharacterCheckTextColour();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCharacterCheckTextColour()
|
||||||
|
{
|
||||||
|
string password = passwordTextBox.Text;
|
||||||
|
|
||||||
|
foreach (var d in characterCheckText.Drawables)
|
||||||
|
d.Colour = password.Length == 0 ? Color4.White : Interpolation.ValueAt(password.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnEntering(IScreen last)
|
public override void OnEntering(IScreen last)
|
||||||
|
@ -12,9 +12,9 @@ using osu.Framework.Graphics.Effects;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -206,7 +206,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
|
|
||||||
getSetsRequest.Success += response =>
|
getSetsRequest.Success += response =>
|
||||||
{
|
{
|
||||||
var sets = response.BeatmapSets.Select(responseJson => responseJson.ToBeatmapSet(rulesets)).ToList();
|
var sets = response.BeatmapSets.ToList();
|
||||||
|
|
||||||
// If the previous request returned a null cursor, the API is indicating we can't paginate further (maybe there are no more beatmaps left).
|
// If the previous request returned a null cursor, the API is indicating we can't paginate further (maybe there are no more beatmaps left).
|
||||||
if (sets.Count == 0 || response.Cursor == null)
|
if (sets.Count == 0 || response.Cursor == null)
|
||||||
@ -289,7 +289,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
/// Contains the beatmap sets returned from API.
|
/// Contains the beatmap sets returned from API.
|
||||||
/// Valid for read if and only if <see cref="Type"/> is <see cref="SearchResultType.ResultsReturned"/>.
|
/// Valid for read if and only if <see cref="Type"/> is <see cref="SearchResultType.ResultsReturned"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<BeatmapSetInfo> Results { get; private set; }
|
public List<APIBeatmapSet> Results { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the names of supporter-only filters requested by the user.
|
/// Contains the names of supporter-only filters requested by the user.
|
||||||
@ -297,7 +297,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<LocalisableString> SupporterOnlyFiltersUsed { get; private set; }
|
public List<LocalisableString> SupporterOnlyFiltersUsed { get; private set; }
|
||||||
|
|
||||||
public static SearchResult ResultsReturned(List<BeatmapSetInfo> results) => new SearchResult
|
public static SearchResult ResultsReturned(List<APIBeatmapSet> results) => new SearchResult
|
||||||
{
|
{
|
||||||
Type = SearchResultType.ResultsReturned,
|
Type = SearchResultType.ResultsReturned,
|
||||||
Results = results
|
Results = results
|
||||||
|
@ -8,12 +8,12 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -49,17 +49,17 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
|
|
||||||
public Bindable<SearchExplicit> ExplicitContent => explicitContentFilter.Current;
|
public Bindable<SearchExplicit> ExplicitContent => explicitContentFilter.Current;
|
||||||
|
|
||||||
public BeatmapSetInfo BeatmapSet
|
public APIBeatmapSet BeatmapSet
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null || string.IsNullOrEmpty(value.OnlineInfo.Covers.Cover))
|
if (value == null || string.IsNullOrEmpty(value.Covers.Cover))
|
||||||
{
|
{
|
||||||
beatmapCover.FadeOut(600, Easing.OutQuint);
|
beatmapCover.FadeOut(600, Easing.OutQuint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beatmapCover.OnlineInfo = value.OnlineInfo;
|
beatmapCover.OnlineInfo = value;
|
||||||
beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint);
|
beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
{
|
{
|
||||||
public abstract class BeatmapPanel : OsuClickableContainer, IHasContextMenu
|
public abstract class BeatmapPanel : OsuClickableContainer, IHasContextMenu
|
||||||
{
|
{
|
||||||
public readonly BeatmapSetInfo SetInfo;
|
public readonly APIBeatmapSet SetInfo;
|
||||||
|
|
||||||
private const double hover_transition_time = 400;
|
private const double hover_transition_time = 400;
|
||||||
private const int maximum_difficulty_icons = 10;
|
private const int maximum_difficulty_icons = 10;
|
||||||
@ -49,10 +50,10 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
|
|
||||||
protected Action ViewBeatmap;
|
protected Action ViewBeatmap;
|
||||||
|
|
||||||
protected BeatmapPanel(BeatmapSetInfo setInfo)
|
protected BeatmapPanel(APIBeatmapSet setInfo)
|
||||||
: base(HoverSampleSet.Submit)
|
: base(HoverSampleSet.Submit)
|
||||||
{
|
{
|
||||||
Debug.Assert(setInfo.OnlineBeatmapSetID != null);
|
Debug.Assert(setInfo.OnlineID > 0);
|
||||||
|
|
||||||
SetInfo = setInfo;
|
SetInfo = setInfo;
|
||||||
}
|
}
|
||||||
@ -95,8 +96,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
|
|
||||||
Action = ViewBeatmap = () =>
|
Action = ViewBeatmap = () =>
|
||||||
{
|
{
|
||||||
Debug.Assert(SetInfo.OnlineBeatmapSetID != null);
|
Debug.Assert(SetInfo.OnlineID > 0);
|
||||||
beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value);
|
beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineID);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,14 +147,14 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
{
|
{
|
||||||
var icons = new List<DifficultyIcon>();
|
var icons = new List<DifficultyIcon>();
|
||||||
|
|
||||||
if (SetInfo.Beatmaps.Count > maximum_difficulty_icons)
|
if (SetInfo.Beatmaps.Length > maximum_difficulty_icons)
|
||||||
{
|
{
|
||||||
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
|
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
|
||||||
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
|
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.Where(b => b.RulesetID == ruleset.OnlineID).ToList(), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.Ruleset.ID).ThenBy(beatmap => beatmap.StarDifficulty))
|
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.RulesetID).ThenBy(beatmap => beatmap.StarRating))
|
||||||
icons.Add(new DifficultyIcon(b));
|
icons.Add(new DifficultyIcon(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +164,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
protected Drawable CreateBackground() => new UpdateableOnlineBeatmapSetCover
|
protected Drawable CreateBackground() => new UpdateableOnlineBeatmapSetCover
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
OnlineInfo = SetInfo.OnlineInfo,
|
OnlineInfo = SetInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
public class Statistic : FillFlowContainer
|
public class Statistic : FillFlowContainer
|
||||||
|
@ -11,6 +11,7 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapListing.Panels
|
namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||||
{
|
{
|
||||||
@ -21,7 +22,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Currently selected beatmap. Used to present the correct difficulty after completing a download.
|
/// Currently selected beatmap. Used to present the correct difficulty after completing a download.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IBindable<BeatmapInfo> SelectedBeatmap = new Bindable<BeatmapInfo>();
|
public readonly IBindable<APIBeatmap> SelectedBeatmap = new Bindable<APIBeatmap>();
|
||||||
|
|
||||||
private readonly ShakeContainer shakeContainer;
|
private readonly ShakeContainer shakeContainer;
|
||||||
private readonly DownloadButton button;
|
private readonly DownloadButton button;
|
||||||
@ -31,9 +32,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
|
|
||||||
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||||
|
|
||||||
private readonly BeatmapSetInfo beatmapSet;
|
private readonly IBeatmapSetInfo beatmapSet;
|
||||||
|
|
||||||
public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet)
|
public BeatmapPanelDownloadButton(IBeatmapSetInfo beatmapSet)
|
||||||
{
|
{
|
||||||
this.beatmapSet = beatmapSet;
|
this.beatmapSet = beatmapSet;
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
case DownloadState.LocallyAvailable:
|
case DownloadState.LocallyAvailable:
|
||||||
Predicate<BeatmapInfo> findPredicate = null;
|
Predicate<BeatmapInfo> findPredicate = null;
|
||||||
if (SelectedBeatmap.Value != null)
|
if (SelectedBeatmap.Value != null)
|
||||||
findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineBeatmapID;
|
findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineID;
|
||||||
|
|
||||||
game?.PresentBeatmap(beatmapSet, findPredicate);
|
game?.PresentBeatmap(beatmapSet, findPredicate);
|
||||||
break;
|
break;
|
||||||
@ -100,7 +101,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (beatmapSet.OnlineInfo?.Availability.DownloadDisabled ?? false)
|
if ((beatmapSet as IBeatmapSetOnlineInfo)?.Availability.DownloadDisabled == true)
|
||||||
{
|
{
|
||||||
button.Enabled.Value = false;
|
button.Enabled.Value = false;
|
||||||
button.TooltipText = "this beatmap is currently not available for download.";
|
button.TooltipText = "this beatmap is currently not available for download.";
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user