1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-18 04:59:52 +08:00

Compare commits

..

205 Commits

211 changed files with 2511 additions and 1596 deletions
+2 -2
View File
@@ -38,7 +38,7 @@ jobs:
run: dotnet build -c Debug -warnaserror osu.Desktop.slnf
- name: Test
run: dotnet test $pwd/*.Tests/bin/Debug/*/*.Tests.dll --blame-crash --blame-hang --blame-hang-timeout 5m --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx"
run: dotnet test $pwd/*.Tests/bin/Debug/*/*.Tests.dll --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx"
shell: pwsh
# Attempt to upload results even if test fails.
@@ -48,7 +48,7 @@ jobs:
if: ${{ always() }}
with:
name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}}
path: ${{github.workspace}}/TestResults/**/*
path: ${{github.workspace}}/TestResults/TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx
build-only-android:
name: Build only (Android)
+2 -1
View File
@@ -8,4 +8,5 @@ M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.
M:osu.Framework.Bindables.IBindableList`1.GetBoundCopy();Fails on iOS. Use manual ctor + BindTo instead. (see https://github.com/mono/mono/issues/19900)
T:Microsoft.EntityFrameworkCore.Internal.EnumerableExtensions;Don't use internal extension methods.
T:Microsoft.EntityFrameworkCore.Internal.TypeExtensions;Don't use internal extension methods.
M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.HasFlagFast<T>() instead.
T:NuGet.Packaging.CollectionExtensions;Don't use internal extension methods.
M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.HasFlagFast<T>() instead.
+1 -1
View File
@@ -52,7 +52,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1112.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1119.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1127.0" />
</ItemGroup>
<ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
+4 -1
View File
@@ -108,7 +108,10 @@ namespace osu.Desktop
presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty);
// update ruleset
presence.Assets.SmallImageKey = ruleset.Value.ID <= 3 ? $"mode_{ruleset.Value.ID}" : "mode_custom";
int onlineID = ruleset.Value.OnlineID;
bool isLegacyRuleset = onlineID >= 0 && onlineID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID;
presence.Assets.SmallImageKey = isLegacyRuleset ? $"mode_{onlineID}" : "mode_custom";
presence.Assets.SmallImageText = ruleset.Value.Name;
client.SetPresence(presence);
@@ -103,7 +103,10 @@ namespace osu.Desktop.Updater
}
else
{
// In the case of an error, a separate notification will be displayed.
notification.State = ProgressNotificationState.Cancelled;
notification.Close();
Logger.Error(e, @"update failed!");
}
}
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
{
var score = decoder.Parse(resourceStream);
Assert.AreEqual(3, score.ScoreInfo.Ruleset.ID);
Assert.AreEqual(3, score.ScoreInfo.Ruleset.OnlineID);
Assert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.Great]);
Assert.AreEqual(1, score.ScoreInfo.Statistics[HitResult.Good]);
@@ -584,7 +584,7 @@ namespace osu.Game.Tests.Beatmaps.IO
{
OnlineID = 1,
Metadata = metadata,
Beatmaps = new List<BeatmapInfo>
Beatmaps =
{
new BeatmapInfo
{
@@ -596,7 +596,7 @@ namespace osu.Game.Tests.Beatmaps.IO
{
OnlineID = 2,
Metadata = metadata,
Status = BeatmapSetOnlineStatus.Loved,
Status = BeatmapOnlineStatus.Loved,
BaseDifficulty = difficulty
}
}
@@ -1050,7 +1050,7 @@ namespace osu.Game.Tests.Beatmaps.IO
private static void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
{
Assert.AreEqual(expected, osu.Dependencies.Get<FileStore>().QueryFiles(f => f.ReferenceCount == 1).Count());
Assert.AreEqual(expected, osu.Dependencies.Get<DatabaseContextFactory>().Get().FileInfo.Count(f => f.ReferenceCount == 1));
}
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)
@@ -100,8 +100,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyEqualsWithDifferentModInstances()
{
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
Assert.That(key1, Is.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
@@ -110,8 +110,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyEqualsWithDifferentModOrder()
{
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() });
Assert.That(key1, Is.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
@@ -120,8 +120,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyDoesntEqualWithDifferentModSettings()
{
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } });
Assert.That(key1, Is.Not.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode()));
@@ -130,8 +130,8 @@ namespace osu.Game.Tests.Beatmaps
[Test]
public void TestKeyEqualWithMatchingModSettings()
{
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { OnlineID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
Assert.That(key1, Is.EqualTo(key2));
Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode()));
@@ -74,6 +74,24 @@ namespace osu.Game.Tests.Database
});
}
[Test]
public void TestAccessFileAfterImport()
{
RunTestWithRealmAsync(async (realmFactory, storage) =>
{
using var importer = new BeatmapImporter(realmFactory, storage);
using var store = new RealmRulesetStore(realmFactory, storage);
var imported = await LoadOszIntoStore(importer, realmFactory.Context);
var beatmap = imported.Beatmaps.First();
var file = beatmap.File;
Assert.NotNull(file);
Assert.AreEqual(beatmap.Hash, file!.File.Hash);
});
}
[Test]
public void TestImportThenDelete()
{
@@ -532,7 +550,7 @@ namespace osu.Game.Tests.Database
new RealmBeatmap(ruleset, new RealmBeatmapDifficulty(), metadata)
{
OnlineID = 2,
Status = BeatmapSetOnlineStatus.Loved,
Status = BeatmapOnlineStatus.Loved,
}
}
};
+21 -5
View File
@@ -6,7 +6,6 @@ using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Models;
using Realms;
@@ -18,18 +17,35 @@ namespace osu.Game.Tests.Database
public class RealmLiveTests : RealmTest
{
[Test]
public void TestLiveCastability()
public void TestLiveEquality()
{
RunTestWithRealm((realmFactory, _) =>
{
RealmLive<RealmBeatmap> beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive();
ILive<RealmBeatmap> beatmap = realmFactory.CreateContext().Write(r => r.Add(new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata()))).ToLive();
ILive<IBeatmapInfo> iBeatmap = beatmap;
ILive<RealmBeatmap> beatmap2 = realmFactory.CreateContext().All<RealmBeatmap>().First().ToLive();
Assert.AreEqual(0, iBeatmap.Value.Length);
Assert.AreEqual(beatmap, beatmap2);
});
}
[Test]
public void TestAccessNonManaged()
{
var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
var liveBeatmap = beatmap.ToLive();
Assert.IsFalse(beatmap.Hidden);
Assert.IsFalse(liveBeatmap.Value.Hidden);
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
Assert.Throws<InvalidOperationException>(() => liveBeatmap.PerformWrite(l => l.Hidden = true));
Assert.IsFalse(beatmap.Hidden);
Assert.IsFalse(liveBeatmap.Value.Hidden);
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
}
[Test]
public void TestValueAccessWithOpenContext()
{
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Moq;
@@ -13,7 +12,6 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Resources;
using FileInfo = osu.Game.IO.FileInfo;
namespace osu.Game.Tests.Editing.Checks
{
@@ -33,14 +31,10 @@ namespace osu.Game.Tests.Editing.Checks
{
BeatmapSet = new BeatmapSetInfo
{
Files = new List<BeatmapSetFileInfo>(new[]
Files =
{
new BeatmapSetFileInfo
{
Filename = "abc123.mp4",
FileInfo = new FileInfo { Hash = "abcdef" }
}
})
CheckTestHelpers.CreateMockFile("mp4"),
}
}
}
};
@@ -1,7 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
@@ -12,7 +12,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Checks;
using osu.Game.Rulesets.Objects;
using FileInfo = osu.Game.IO.FileInfo;
namespace osu.Game.Tests.Editing.Checks
{
@@ -25,25 +24,17 @@ namespace osu.Game.Tests.Editing.Checks
[SetUp]
public void Setup()
{
var file = CheckTestHelpers.CreateMockFile("jpg");
check = new CheckBackgroundQuality();
beatmap = new Beatmap<HitObject>
{
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata { BackgroundFile = "abc123.jpg" },
Metadata = new BeatmapMetadata { BackgroundFile = file.Filename },
BeatmapSet = new BeatmapSetInfo
{
Files = new List<BeatmapSetFileInfo>(new[]
{
new BeatmapSetFileInfo
{
Filename = "abc123.jpg",
FileInfo = new FileInfo
{
Hash = "abcdef"
}
}
})
Files = { file }
}
}
};
@@ -54,7 +45,7 @@ namespace osu.Game.Tests.Editing.Checks
{
// While this is a problem, it is out of scope for this check and is caught by a different one.
beatmap.Metadata.BackgroundFile = string.Empty;
var context = getContext(null, new MemoryStream(System.Array.Empty<byte>()));
var context = getContext(null, new MemoryStream(Array.Empty<byte>()));
Assert.That(check.Run(context), Is.Empty);
}
@@ -1,11 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.IO;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Checks;
using osu.Game.Rulesets.Objects;
@@ -22,22 +20,17 @@ namespace osu.Game.Tests.Editing.Checks
[SetUp]
public void Setup()
{
var file = CheckTestHelpers.CreateMockFile("jpg");
check = new CheckBackgroundPresence();
beatmap = new Beatmap<HitObject>
{
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata { BackgroundFile = "abc123.jpg" },
Metadata = new BeatmapMetadata { BackgroundFile = file.Filename },
BeatmapSet = new BeatmapSetInfo
{
Files = new List<BeatmapSetFileInfo>(new[]
{
new BeatmapSetFileInfo
{
Filename = "abc123.jpg",
FileInfo = new FileInfo { Hash = "abcdef" }
}
})
Files = { file }
}
}
};
@@ -0,0 +1,18 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Beatmaps;
using osu.Game.IO;
namespace osu.Game.Tests.Editing.Checks
{
public static class CheckTestHelpers
{
public static BeatmapSetFileInfo CreateMockFile(string extension) =>
new BeatmapSetFileInfo
{
Filename = $"abc123.{extension}",
FileInfo = new FileInfo { Hash = "abcdef" }
};
}
}
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ManagedBass;
@@ -14,7 +13,6 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Tests.Beatmaps;
using osu.Game.Tests.Resources;
using osuTK.Audio;
using FileInfo = osu.Game.IO.FileInfo;
namespace osu.Game.Tests.Editing.Checks
{
@@ -34,14 +32,7 @@ namespace osu.Game.Tests.Editing.Checks
{
BeatmapSet = new BeatmapSetInfo
{
Files = new List<BeatmapSetFileInfo>(new[]
{
new BeatmapSetFileInfo
{
Filename = "abc123.wav",
FileInfo = new FileInfo { Hash = "abcdef" }
}
})
Files = { CheckTestHelpers.CreateMockFile("wav") }
}
}
};
@@ -55,11 +46,7 @@ namespace osu.Game.Tests.Editing.Checks
public void TestDifferentExtension()
{
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
beatmap.BeatmapInfo.BeatmapSet.Files.Add(new BeatmapSetFileInfo
{
Filename = "abc123.jpg",
FileInfo = new FileInfo { Hash = "abcdef" }
});
beatmap.BeatmapInfo.BeatmapSet.Files.Add(CheckTestHelpers.CreateMockFile("jpg"));
// Should fail to load, but not produce an error due to the extension not being expected to load.
Assert.IsEmpty(check.Run(getContext(null, allowMissing: true)));
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Moq;
@@ -10,7 +9,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Checks;
using osu.Game.Rulesets.Objects;
using FileInfo = osu.Game.IO.FileInfo;
namespace osu.Game.Tests.Editing.Checks
{
@@ -30,14 +28,10 @@ namespace osu.Game.Tests.Editing.Checks
{
BeatmapSet = new BeatmapSetInfo
{
Files = new List<BeatmapSetFileInfo>(new[]
Files =
{
new BeatmapSetFileInfo
{
Filename = "abc123.jpg",
FileInfo = new FileInfo { Hash = "abcdef" }
}
})
CheckTestHelpers.CreateMockFile("jpg"),
}
}
}
};
+6 -6
View File
@@ -29,9 +29,9 @@ namespace osu.Game.Tests.Models
{
var mock = new Mock<IBeatmapSetInfo>();
mock.Setup(m => m.Metadata!.Artist).Returns("artist");
mock.Setup(m => m.Metadata!.Title).Returns("title");
mock.Setup(m => m.Metadata!.Author.Username).Returns("author");
mock.Setup(m => m.Metadata.Artist).Returns("artist");
mock.Setup(m => m.Metadata.Title).Returns("title");
mock.Setup(m => m.Metadata.Author.Username).Returns("author");
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title (author)"));
}
@@ -41,9 +41,9 @@ namespace osu.Game.Tests.Models
{
var mock = new Mock<IBeatmapSetInfo>();
mock.Setup(m => m.Metadata!.Artist).Returns("artist");
mock.Setup(m => m.Metadata!.Title).Returns("title");
mock.Setup(m => m.Metadata!.Author.Username).Returns(string.Empty);
mock.Setup(m => m.Metadata.Artist).Returns("artist");
mock.Setup(m => m.Metadata.Title).Returns("title");
mock.Setup(m => m.Metadata.Author.Username).Returns(string.Empty);
Assert.That(mock.Object.GetDisplayString(), Is.EqualTo("artist - title"));
}
@@ -16,7 +16,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
{
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
{
Ruleset = new RulesetInfo { ID = 5 },
Ruleset = new RulesetInfo { OnlineID = 5 },
StarRating = 4.0d,
BaseDifficulty = new BeatmapDifficulty
{
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
Length = 2500,
BPM = 160,
BeatDivisor = 12,
Status = BeatmapSetOnlineStatus.Loved
Status = BeatmapOnlineStatus.Loved
};
[Test]
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
var exampleBeatmapInfo = getExampleBeatmap();
var criteria = new FilterCriteria
{
Ruleset = new RulesetInfo { ID = 6 }
Ruleset = new RulesetInfo { OnlineID = 6 }
};
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
carouselItem.Filter(criteria);
@@ -70,7 +70,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
var exampleBeatmapInfo = getExampleBeatmap();
var criteria = new FilterCriteria
{
Ruleset = new RulesetInfo { ID = 6 },
Ruleset = new RulesetInfo { OnlineID = 6 },
AllowConvertedBeatmaps = true
};
var carouselItem = new CarouselBeatmap(exampleBeatmapInfo);
@@ -86,7 +86,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
var exampleBeatmapInfo = getExampleBeatmap();
var criteria = new FilterCriteria
{
Ruleset = new RulesetInfo { ID = 6 },
Ruleset = new RulesetInfo { OnlineID = 6 },
AllowConvertedBeatmaps = true,
ApproachRate = new FilterCriteria.OptionalRange<float>
{
@@ -107,7 +107,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
var exampleBeatmapInfo = getExampleBeatmap();
var criteria = new FilterCriteria
{
Ruleset = new RulesetInfo { ID = 6 },
Ruleset = new RulesetInfo { OnlineID = 6 },
AllowConvertedBeatmaps = true,
BPM = new FilterCriteria.OptionalRange<double>
{
@@ -132,7 +132,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
var exampleBeatmapInfo = getExampleBeatmap();
var criteria = new FilterCriteria
{
Ruleset = new RulesetInfo { ID = 6 },
Ruleset = new RulesetInfo { OnlineID = 6 },
AllowConvertedBeatmaps = true,
SearchText = terms
};
@@ -162,9 +162,9 @@ namespace osu.Game.Tests.NonVisual.Filtering
FilterQueryParser.ApplyQueries(filterCriteria, query);
Assert.AreEqual("I want the pp", filterCriteria.SearchText.Trim());
Assert.AreEqual(4, filterCriteria.SearchTerms.Length);
Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Min);
Assert.AreEqual(BeatmapOnlineStatus.Ranked, filterCriteria.OnlineStatus.Min);
Assert.IsTrue(filterCriteria.OnlineStatus.IsLowerInclusive);
Assert.AreEqual(BeatmapSetOnlineStatus.Ranked, filterCriteria.OnlineStatus.Max);
Assert.AreEqual(BeatmapOnlineStatus.Ranked, filterCriteria.OnlineStatus.Max);
Assert.IsTrue(filterCriteria.OnlineStatus.IsUpperInclusive);
}
@@ -72,7 +72,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
RoomManager.CreateRoom(newRoom);
});
AddUntilStep("wait for room join", () => Client.Room != null);
AddUntilStep("wait for room join", () => RoomJoined);
checkPlayingUserCount(1);
}
@@ -12,9 +12,9 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Tests.Online
{
[HeadlessTest]
public class TestSceneBeatmapManager : OsuTestScene
public class TestSceneBeatmapDownloading : OsuTestScene
{
private BeatmapManager beatmaps;
private BeatmapModelDownloader beatmaps;
private ProgressNotification recentNotification;
private static readonly BeatmapSetInfo test_db_model = new BeatmapSetInfo
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Online
};
[BackgroundDependencyLoader]
private void load(BeatmapManager beatmaps)
private void load(BeatmapModelDownloader beatmaps)
{
this.beatmaps = beatmaps;
@@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -33,6 +33,7 @@ namespace osu.Game.Tests.Online
{
private RulesetStore rulesets;
private TestBeatmapManager beatmaps;
private TestBeatmapModelDownloader beatmapDownloader;
private string testBeatmapFile;
private BeatmapInfo testBeatmapInfo;
@@ -46,6 +47,7 @@ namespace osu.Game.Tests.Online
{
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.CacheAs<BeatmapManager>(beatmaps = new TestBeatmapManager(LocalStorage, ContextFactory, rulesets, API, audio, Resources, host, Beatmap.Default));
Dependencies.CacheAs<BeatmapModelDownloader>(beatmapDownloader = new TestBeatmapModelDownloader(beatmaps, API, host));
}
[SetUp]
@@ -80,13 +82,13 @@ namespace osu.Game.Tests.Online
AddAssert("ensure beatmap unavailable", () => !beatmaps.IsAvailableLocally(testBeatmapSet));
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
AddStep("start downloading", () => beatmaps.Download(testBeatmapSet));
AddStep("start downloading", () => beatmapDownloader.Download(testBeatmapSet));
addAvailabilityCheckStep("state downloading 0%", () => BeatmapAvailability.Downloading(0.0f));
AddStep("set progress 40%", () => ((TestDownloadRequest)beatmaps.GetExistingDownload(testBeatmapSet)).SetProgress(0.4f));
AddStep("set progress 40%", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet)).SetProgress(0.4f));
addAvailabilityCheckStep("state downloading 40%", () => BeatmapAvailability.Downloading(0.4f));
AddStep("finish download", () => ((TestDownloadRequest)beatmaps.GetExistingDownload(testBeatmapSet)).TriggerSuccess(testBeatmapFile));
AddStep("finish download", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet)).TriggerSuccess(testBeatmapFile));
addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing);
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
@@ -143,7 +145,10 @@ namespace osu.Game.Tests.Online
var beatmap = decoder.Decode(reader);
info = beatmap.BeatmapInfo;
info.BeatmapSet.Beatmaps = new List<BeatmapInfo> { info };
Debug.Assert(info.BeatmapSet != null);
info.BeatmapSet.Beatmaps.Add(info);
info.BeatmapSet.Metadata = info.Metadata;
info.MD5Hash = stream.ComputeMD5Hash();
info.Hash = stream.ComputeSHA2Hash();
@@ -168,22 +173,6 @@ namespace osu.Game.Tests.Online
return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host);
}
protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> manager, IAPIProvider api, GameHost host)
{
return new TestBeatmapModelDownloader(manager, api, host);
}
internal class TestBeatmapModelDownloader : BeatmapModelDownloader
{
public TestBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> importer, IAPIProvider apiProvider, GameHost gameHost)
: base(importer, apiProvider, gameHost)
{
}
protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize)
=> new TestDownloadRequest(set);
}
internal class TestBeatmapModelManager : BeatmapModelManager
{
private readonly TestBeatmapManager testBeatmapManager;
@@ -202,6 +191,17 @@ namespace osu.Game.Tests.Online
}
}
internal class TestBeatmapModelDownloader : BeatmapModelDownloader
{
public TestBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> importer, IAPIProvider apiProvider, GameHost gameHost)
: base(importer, apiProvider)
{
}
protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize)
=> new TestDownloadRequest(set);
}
private class TestDownloadRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
{
public new void SetProgress(float progress) => base.SetProgress(progress);
+81
View File
@@ -2,10 +2,18 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using NUnit.Framework;
using osu.Framework.Extensions;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
namespace osu.Game.Tests.Resources
{
@@ -56,5 +64,78 @@ namespace osu.Game.Tests.Resources
}
private static string getTempFilename() => temp_storage.GetFullPath(Guid.NewGuid() + ".osz");
private static int importId;
/// <summary>
/// Create a test beatmap set model.
/// </summary>
/// <param name="difficultyCount">Number of difficulties. If null, a random number between 1 and 20 will be used.</param>
/// <param name="rulesets">Rulesets to cycle through when creating difficulties. If <c>null</c>, osu! ruleset will be used.</param>
public static BeatmapSetInfo CreateTestBeatmapSetInfo(int? difficultyCount = null, RulesetInfo[] rulesets = null)
{
int j = 0;
RulesetInfo getRuleset() => rulesets?[j++ % rulesets.Length] ?? new OsuRuleset().RulesetInfo;
int setId = Interlocked.Increment(ref importId);
var metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
Title = $"Some Song (set id {setId}) {Guid.NewGuid()}",
AuthorString = "Some Guy " + RNG.Next(0, 9),
};
var beatmapSet = new BeatmapSetInfo
{
OnlineID = setId,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
DateAdded = DateTimeOffset.UtcNow,
Metadata = metadata
};
foreach (var b in getBeatmaps(difficultyCount ?? RNG.Next(1, 20)))
beatmapSet.Beatmaps.Add(b);
return beatmapSet;
IEnumerable<BeatmapInfo> getBeatmaps(int count)
{
for (int i = 0; i < count; i++)
{
int beatmapId = setId * 1000 + i;
int length = RNG.Next(30000, 200000);
double bpm = RNG.NextSingle(80, 200);
float diff = (float)i / count * 10;
string version = "Normal";
if (diff > 6.6)
version = "Insane";
else if (diff > 3.3)
version = "Hard";
var rulesetInfo = getRuleset();
yield return new BeatmapInfo
{
OnlineID = beatmapId,
DifficultyName = $"{version} {beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
StarRating = diff,
Length = length,
BPM = bpm,
Ruleset = rulesetInfo,
RulesetID = rulesetInfo.ID ?? -1,
Metadata = metadata,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = diff,
}
};
}
}
}
}
}
+1 -1
View File
@@ -142,7 +142,7 @@ namespace osu.Game.Tests.Scores.IO
var scoreManager = osu.Dependencies.Get<ScoreManager>();
beatmapManager.Delete(beatmapManager.QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == imported.BeatmapInfo.ID)));
Assert.That(scoreManager.Query(s => s.ID == imported.ID).DeletePending, Is.EqualTo(true));
Assert.That(scoreManager.Query(s => s.Equals(imported)).DeletePending, Is.EqualTo(true));
var secondImport = await LoadScoreIntoOsu(osu, imported);
Assert.That(secondImport, Is.Null);
@@ -70,7 +70,7 @@ namespace osu.Game.Tests.Testing
{
// temporary ID to let RulesetConfigCache pass our
// config manager to the ruleset dependencies.
RulesetInfo.ID = -1;
RulesetInfo.OnlineID = -1;
}
public override IResourceStore<byte[]> CreateResourceStore() => new NamespacedResourceStore<byte[]>(TestResources.GetStore(), @"Resources");
@@ -23,6 +23,11 @@ namespace osu.Game.Tests.Visual.Beatmaps
{
public class TestSceneBeatmapCard : OsuTestScene
{
/// <summary>
/// All cards on this scene use a common online ID to ensure that map download, preview tracks, etc. can be tested manually with online sources.
/// </summary>
private const int online_id = 163112;
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
private APIBeatmapSet[] testCases;
@@ -38,11 +43,10 @@ namespace osu.Game.Tests.Visual.Beatmaps
var normal = CreateAPIBeatmapSet(Ruleset.Value);
normal.HasVideo = true;
normal.HasStoryboard = true;
normal.OnlineID = 241526;
var withStatistics = CreateAPIBeatmapSet(Ruleset.Value);
withStatistics.Title = withStatistics.TitleUnicode = "play favourite stats";
withStatistics.Status = BeatmapSetOnlineStatus.Approved;
withStatistics.Status = BeatmapOnlineStatus.Approved;
withStatistics.FavouriteCount = 284_239;
withStatistics.PlayCount = 999_001;
withStatistics.Ranked = DateTimeOffset.Now.AddDays(-45);
@@ -63,7 +67,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
var someDifficulties = getManyDifficultiesBeatmapSet(11);
someDifficulties.Title = someDifficulties.TitleUnicode = "favourited";
someDifficulties.Title = someDifficulties.TitleUnicode = "some difficulties";
someDifficulties.Status = BeatmapSetOnlineStatus.Qualified;
someDifficulties.Status = BeatmapOnlineStatus.Qualified;
someDifficulties.HasFavourited = true;
someDifficulties.FavouriteCount = 1;
someDifficulties.NominationStatus = new BeatmapSetNominationStatus
@@ -73,7 +77,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
};
var manyDifficulties = getManyDifficultiesBeatmapSet(100);
manyDifficulties.Status = BeatmapSetOnlineStatus.Pending;
manyDifficulties.Status = BeatmapOnlineStatus.Pending;
var explicitMap = CreateAPIBeatmapSet(Ruleset.Value);
explicitMap.Title = someDifficulties.TitleUnicode = "explicit beatmap";
@@ -106,6 +110,9 @@ namespace osu.Game.Tests.Visual.Beatmaps
explicitFeaturedMap,
longName
};
foreach (var testCase in testCases)
testCase.OnlineID = online_id;
}
private APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
@@ -191,9 +198,9 @@ namespace osu.Game.Tests.Visual.Beatmaps
private void ensureSoleilyRemoved()
{
AddUntilStep("ensure manager loaded", () => beatmaps != null);
AddStep("remove soleily", () =>
AddStep("remove map", () =>
{
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineID == 241526);
var beatmap = beatmaps.QueryBeatmapSet(b => b.OnlineID == online_id);
if (beatmap != null) beatmaps.Delete(beatmap);
});
@@ -0,0 +1,84 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Beatmaps.Drawables.Cards.Buttons;
using osu.Game.Overlays;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Beatmaps
{
public class TestSceneBeatmapCardThumbnail : OsuManualInputManagerTestScene
{
private PlayButton playButton => this.ChildrenOfType<PlayButton>().Single();
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
[Test]
public void TestThumbnailPreview()
{
BeatmapCardThumbnail thumbnail = null;
AddStep("create thumbnail", () =>
{
var beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSet.OnlineID = 241526; // ID hardcoded to ensure that the preview track exists online.
Child = thumbnail = new BeatmapCardThumbnail(beatmapSet)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200)
};
});
AddStep("enable dim", () => thumbnail.Dimmed.Value = true);
AddUntilStep("button visible", () => playButton.IsPresent);
AddStep("click button", () =>
{
InputManager.MoveMouseTo(playButton);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for start", () => playButton.Playing.Value && playButton.Enabled.Value);
iconIs(FontAwesome.Solid.Stop);
AddStep("click again", () =>
{
InputManager.MoveMouseTo(playButton);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for stop", () => !playButton.Playing.Value && playButton.Enabled.Value);
iconIs(FontAwesome.Solid.Play);
AddStep("click again", () =>
{
InputManager.MoveMouseTo(playButton);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for start", () => playButton.Playing.Value && playButton.Enabled.Value);
iconIs(FontAwesome.Solid.Stop);
AddStep("disable dim", () => thumbnail.Dimmed.Value = false);
AddWaitStep("wait some", 3);
AddAssert("button still visible", () => playButton.IsPresent);
// The track plays in real-time, so we need to check for progress in increments to avoid timeout.
AddUntilStep("progress > 0.25", () => thumbnail.ChildrenOfType<PlayButton>().Single().Progress.Value > 0.25);
AddUntilStep("progress > 0.5", () => thumbnail.ChildrenOfType<PlayButton>().Single().Progress.Value > 0.5);
AddUntilStep("progress > 0.75", () => thumbnail.ChildrenOfType<PlayButton>().Single().Progress.Value > 0.75);
AddUntilStep("wait for track to end", () => !playButton.Playing.Value);
AddUntilStep("button hidden", () => !playButton.IsPresent);
}
private void iconIs(IconUsage usage) => AddUntilStep("icon is correct", () => playButton.ChildrenOfType<SpriteIcon>().Any(icon => icon.Icon.Equals(usage)));
}
}
@@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
Origin = Anchor.Centre,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
ChildrenEnumerable = Enum.GetValues(typeof(BeatmapSetOnlineStatus)).Cast<BeatmapSetOnlineStatus>().Select(status => new BeatmapSetOnlineStatusPill
ChildrenEnumerable = Enum.GetValues(typeof(BeatmapOnlineStatus)).Cast<BeatmapOnlineStatus>().Select(status => new BeatmapSetOnlineStatusPill
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
@@ -69,7 +69,10 @@ namespace osu.Game.Tests.Visual.Editing
AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
PushAndConfirm(() => new PlaySongSelect());
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new PlaySongSelect());
AddUntilStep("wait for carousel load", () => songSelect.BeatmapSetsLoaded);
AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault);
AddStep("Open options", () => InputManager.Key(Key.F3));
@@ -233,7 +233,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
prepareTokenResponse(true);
createPlayerTest(false, createRuleset: () => new OsuRuleset { RulesetInfo = { ID = rulesetId } });
createPlayerTest(false, createRuleset: () => new OsuRuleset { RulesetInfo = { OnlineID = rulesetId ?? -1 } });
AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
@@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
new Drawable[]
{
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
recordingManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
Recorder = recorder = new TestReplayRecorder(new Score
{
@@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Gameplay
},
new Drawable[]
{
playbackManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
playbackManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
{
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
new Drawable[]
{
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
recordingManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
Recorder = new TestReplayRecorder(new Score
{
@@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay
},
new Drawable[]
{
playbackManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
playbackManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
{
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestClientSendsCorrectRuleset()
{
AddUntilStep("spectator client sending frames", () => spectatorClient.PlayingUserStates.ContainsKey(dummy_user_id));
AddAssert("spectator client sent correct ruleset", () => spectatorClient.PlayingUserStates[dummy_user_id].RulesetID == Ruleset.Value.ID);
AddAssert("spectator client sent correct ruleset", () => spectatorClient.PlayingUserStates[dummy_user_id].RulesetID == Ruleset.Value.OnlineID);
}
public override void TearDownSteps()
@@ -109,7 +109,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
new Drawable[]
{
recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
recordingManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
Recorder = recorder = new TestReplayRecorder
{
@@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.Gameplay
},
new Drawable[]
{
playbackManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
playbackManager = new TestRulesetInputManager(TestSceneModSettings.CreateTestRulesetInfo(), 0, SimultaneousBindingMode.Unique)
{
Clock = new FramedClock(manualClock),
ReplayInputHandler = replayHandler = new TestFramedReplayInputHandler(replay)
@@ -30,25 +30,10 @@ namespace osu.Game.Tests.Visual.Menus
[Test]
public void TestMusicNavigationActions()
{
int importId = 0;
Queue<(IWorkingBeatmap working, TrackChangeDirection changeDirection)> trackChangeQueue = null;
// ensure we have at least two beatmaps available to identify the direction the music controller navigated to.
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(new BeatmapSetInfo
{
Beatmaps = new List<BeatmapInfo>
{
new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty(),
}
},
Metadata = new BeatmapMetadata
{
Artist = $"a test map {importId++}",
Title = "title",
}
}).Wait(), 5);
AddRepeatStep("import beatmap", () => Game.BeatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()).Wait(), 5);
AddStep("import beatmap with track", () =>
{
@@ -5,6 +5,7 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
@@ -92,7 +93,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for join", () => Client.Room != null);
AddUntilStep("wait for join", () => RoomManager.RoomJoined);
}
[Test]
@@ -104,23 +105,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
protected void RunGameplay()
{
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
AddStep("click ready button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerReadyButton>().Single());
InputManager.Click(MouseButton.Left);
});
clickReadyButton();
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
AddStep("click ready button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerReadyButton>().Single());
InputManager.Click(MouseButton.Left);
});
clickReadyButton();
AddUntilStep("wait for player", () => multiplayerScreenStack.CurrentScreen is Player player && player.IsLoaded);
AddStep("exit player", () => multiplayerScreenStack.MultiplayerScreen.MakeCurrent());
}
private void clickReadyButton()
{
AddUntilStep("wait for ready button to be enabled", () => this.ChildrenOfType<MultiplayerReadyButton>().Single().ChildrenOfType<Button>().Single().Enabled.Value);
AddStep("click ready button", () =>
{
InputManager.MoveMouseTo(this.ChildrenOfType<MultiplayerReadyButton>().Single());
InputManager.Click(MouseButton.Left);
});
}
}
}
@@ -78,6 +78,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("playlist item is not expired", () => Client.APIRoom?.Playlist[1].Expired == false);
}
[Test]
public void TestCorrectItemSelectedAfterNewItemAdded()
{
addItem(() => OtherBeatmap);
AddAssert("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
}
private void addItem(Func<BeatmapInfo> beatmap)
{
AddStep("click edit button", () =>
@@ -86,7 +93,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.IsLoaded);
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded);
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(beatmap()));
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
}
@@ -13,6 +13,7 @@ using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
@@ -22,6 +23,7 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Tests.Beatmaps;
using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Input;
@@ -34,6 +36,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
private BeatmapManager manager;
private RulesetStore rulesets;
[Cached(typeof(UserLookupCache))]
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache();
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
@@ -304,6 +309,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
}
[TestCase(false)]
[TestCase(true)]
public void TestWithOwner(bool withOwner)
{
createPlaylist(false, false, withOwner);
AddAssert("owner visible", () => playlist.ChildrenOfType<UpdateableAvatar>().All(a => a.IsPresent == withOwner));
}
private void moveToItem(int index, Vector2? offset = null)
=> AddStep($"move mouse to item {index}", () => InputManager.MoveMouseTo(playlist.ChildrenOfType<DifficultyIcon>().ElementAt(index), offset));
@@ -327,11 +341,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
=> AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible",
() => (playlist.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistRemoveButton>().ElementAt(2 + index * 2).Alpha > 0) == visible);
private void createPlaylist(bool allowEdit, bool allowSelection)
private void createPlaylist(bool allowEdit, bool allowSelection, bool showItemOwner = false)
{
AddStep("create playlist", () =>
{
Child = playlist = new TestPlaylist(allowEdit, allowSelection)
Child = playlist = new TestPlaylist(allowEdit, allowSelection, showItemOwner)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -343,6 +357,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
playlist.Items.Add(new PlaylistItem
{
ID = i,
OwnerID = 2,
Beatmap =
{
Value = i % 2 == 1
@@ -390,6 +405,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
playlist.Items.Add(new PlaylistItem
{
ID = index++,
OwnerID = 2,
Beatmap = { Value = b },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
@@ -409,8 +425,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public new IReadOnlyDictionary<PlaylistItem, RearrangeableListItem<PlaylistItem>> ItemMap => base.ItemMap;
public TestPlaylist(bool allowEdit, bool allowSelection)
: base(allowEdit, allowSelection)
public TestPlaylist(bool allowEdit, bool allowSelection, bool showItemOwner = false)
: base(allowEdit, allowSelection, showItemOwner: showItemOwner)
{
}
}
@@ -63,6 +63,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("second playlist item changed", () => Client.APIRoom?.Playlist[1].Beatmap.Value != firstBeatmap);
}
[Test]
public void TestSettingsUpdatedWhenChangingQueueMode()
{
AddStep("change queue mode", () => Client.ChangeSettings(new MultiplayerRoomSettings
{
QueueMode = QueueMode.AllPlayers
}));
AddUntilStep("api room updated", () => Client.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
}
private void selectNewItem(Func<BeatmapInfo> beatmap)
{
AddStep("click edit button", () =>
@@ -71,7 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.IsLoaded);
AddUntilStep("wait for song select", () => CurrentSubScreen is Screens.Select.SongSelect select && select.BeatmapSetsLoaded);
BeatmapInfo otherBeatmap = null;
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap()));
@@ -204,7 +204,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
// edit playlist item
AddStep("Press select", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for song select", () => InputManager.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault() != null);
AddUntilStep("wait for song select", () => InputManager.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
// select beatmap
AddStep("Press select", () => InputManager.Key(Key.Enter));
@@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("Press select", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.Room != null);
AddUntilStep("wait for join", () => roomManager.RoomJoined);
}
[Test]
@@ -253,7 +253,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@@ -293,7 +293,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join room", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.Room != null);
AddUntilStep("wait for join", () => roomManager.RoomJoined);
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);
@@ -336,7 +336,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@@ -351,7 +351,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.Room != null);
AddUntilStep("wait for join", () => roomManager.RoomJoined);
}
[Test]
@@ -597,7 +597,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Ruleset = { Value = new OsuRuleset().RulesetInfo },
}
}
});
}, API.LocalUser.Value);
});
AddStep("refresh rooms", () => this.ChildrenOfType<LoungeSubScreen>().Single().UpdateFilter());
@@ -618,7 +618,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("join room", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
AddUntilStep("wait for join", () => client.Room != null);
AddUntilStep("wait for join", () => roomManager.RoomJoined);
AddAssert("local room has correct settings", () =>
{
@@ -644,7 +644,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for join", () => client.Room != null);
AddUntilStep("wait for join", () => roomManager.RoomJoined);
}
}
}
@@ -47,6 +47,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
beatmaps = new List<BeatmapInfo>();
var metadata = new BeatmapMetadata
{
Artist = "Some Artist",
Title = "Some Beatmap",
AuthorString = "Some Author"
};
var beatmapSetInfo = new BeatmapSetInfo
{
OnlineID = 10,
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Metadata = metadata,
DateAdded = DateTimeOffset.UtcNow
};
for (int i = 0; i < 8; ++i)
{
int beatmapId = 10 * 10 + i;
@@ -54,29 +69,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
int length = RNG.Next(30000, 200000);
double bpm = RNG.NextSingle(80, 200);
beatmaps.Add(new BeatmapInfo
var beatmap = new BeatmapInfo
{
Ruleset = rulesets.GetRuleset(i % 4),
OnlineID = beatmapId,
Length = length,
BPM = bpm,
Metadata = metadata,
BaseDifficulty = new BeatmapDifficulty()
});
};
beatmaps.Add(beatmap);
beatmapSetInfo.Beatmaps.Add(beatmap);
}
manager.Import(new BeatmapSetInfo
{
OnlineID = 10,
Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
Artist = "Some Artist",
Title = "Some Beatmap",
AuthorString = "Some Author"
},
Beatmaps = beatmaps,
DateAdded = DateTimeOffset.UtcNow
}).Wait();
manager.Import(beatmapSetInfo).Wait();
}
public override void SetUpSteps()
@@ -91,7 +98,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect(SelectedRoom.Value)));
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded);
}
[Test]
@@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
});
AddUntilStep("wait for join", () => Client.Room != null);
AddUntilStep("wait for join", () => RoomJoined);
}
[Test]
@@ -116,7 +116,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for room join", () => Client.Room != null);
AddUntilStep("wait for room join", () => RoomJoined);
AddStep("join other user (ready)", () =>
{
@@ -9,6 +9,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Framework.Utils;
@@ -198,11 +199,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
}, users);
}
private void addClickButtonStep() => AddStep("click button", () =>
private void addClickButtonStep()
{
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for button to be ready", () => button.ChildrenOfType<Button>().Single().Enabled.Value);
AddStep("click button", () =>
{
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
}
private void verifyGameplayStartFlow()
{
@@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
PlaylistItem playlistItem = new PlaylistItem
{
BeatmapID = beatmapInfo.ID,
BeatmapID = beatmapInfo.OnlineID ?? -1,
};
Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem));
@@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
PlaylistItem playlistItem = new PlaylistItem
{
BeatmapID = beatmapInfo.ID,
BeatmapID = beatmapInfo.OnlineID ?? -1,
};
SortedDictionary<int, BindableInt> teamScores = new SortedDictionary<int, BindableInt>
@@ -2,14 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Utils;
@@ -21,6 +17,7 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Resources;
using osu.Game.Tests.Visual.OnlinePlay;
namespace osu.Game.Tests.Visual.Multiplayer
@@ -42,43 +39,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Dependencies.Cache(rulesets = new RulesetStore(ContextFactory));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default));
var beatmaps = new List<BeatmapInfo>();
var beatmapSet = TestResources.CreateTestBeatmapSetInfo();
for (int i = 0; i < 6; i++)
{
int beatmapId = 10 * 10 + i;
int length = RNG.Next(30000, 200000);
double bpm = RNG.NextSingle(80, 200);
beatmaps.Add(new BeatmapInfo
{
Ruleset = new OsuRuleset().RulesetInfo,
OnlineID = beatmapId,
DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
Length = length,
BPM = bpm,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
},
});
}
manager.Import(new BeatmapSetInfo
{
OnlineID = 10,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
Title = $"Some Song (set id 10), max bpm {beatmaps.Max(b => b.BPM):0.#})",
AuthorString = "Some Guy " + RNG.Next(0, 9),
},
Beatmaps = beatmaps,
DateAdded = DateTimeOffset.UtcNow,
}).Wait();
manager.Import(beatmapSet).Wait();
}
public override void SetUpSteps()
@@ -94,7 +57,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect(SelectedRoom.Value)));
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen());
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded);
}
[Test]
@@ -158,7 +158,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for join", () => client.Room != null);
AddUntilStep("wait for join", () => multiplayerScreenStack.RoomManager.RoomJoined);
}
}
}
@@ -2,7 +2,6 @@
// 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.Screens;
@@ -110,7 +109,7 @@ namespace osu.Game.Tests.Visual.Navigation
Hash = Guid.NewGuid().ToString(),
OnlineID = i,
Metadata = metadata,
Beatmaps = new List<BeatmapInfo>
Beatmaps =
{
new BeatmapInfo
{
@@ -141,7 +140,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.MatchesOnlineID(getImport()));
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Beatmaps.First().Ruleset));
}
private void presentSecondDifficultyAndConfirm(Func<BeatmapSetInfo> getImport, int importedID)
@@ -151,7 +150,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID == importedID * 2048);
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Beatmaps.First().Ruleset));
}
}
}
@@ -2,7 +2,6 @@
// 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.Screens;
@@ -41,7 +40,7 @@ namespace osu.Game.Tests.Visual.Navigation
Hash = Guid.NewGuid().ToString(),
OnlineID = 1,
Metadata = metadata,
Beatmaps = new List<BeatmapInfo>
Beatmaps =
{
new BeatmapInfo
{
@@ -155,15 +154,15 @@ namespace osu.Game.Tests.Visual.Navigation
case ScorePresentType.Results:
AddUntilStep("wait for results", () => lastWaitedScreen != Game.ScreenStack.CurrentScreen && Game.ScreenStack.CurrentScreen is ResultsScreen);
AddStep("store last waited screen", () => lastWaitedScreen = Game.ScreenStack.CurrentScreen);
AddUntilStep("correct score displayed", () => ((ResultsScreen)Game.ScreenStack.CurrentScreen).Score.ID == getImport().ID);
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Ruleset.ID);
AddUntilStep("correct score displayed", () => ((ResultsScreen)Game.ScreenStack.CurrentScreen).Score.Equals(getImport()));
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Ruleset));
break;
case ScorePresentType.Gameplay:
AddUntilStep("wait for player loader", () => lastWaitedScreen != Game.ScreenStack.CurrentScreen && Game.ScreenStack.CurrentScreen is ReplayPlayerLoader);
AddStep("store last waited screen", () => lastWaitedScreen = Game.ScreenStack.CurrentScreen);
AddUntilStep("correct score displayed", () => ((ReplayPlayerLoader)Game.ScreenStack.CurrentScreen).Score.ID == getImport().ID);
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Ruleset.ID);
AddUntilStep("correct score displayed", () => ((ReplayPlayerLoader)Game.ScreenStack.CurrentScreen).Score.Equals(getImport()));
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Ruleset));
break;
}
}
@@ -66,7 +66,9 @@ namespace osu.Game.Tests.Visual.Navigation
{
Player player = null;
PushAndConfirm(() => new TestPlaySongSelect());
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
@@ -98,7 +100,9 @@ namespace osu.Game.Tests.Visual.Navigation
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
PushAndConfirm(() => new TestPlaySongSelect());
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
AddStep("import beatmap", () => ImportBeatmapTest.LoadQuickOszIntoOsu(Game).Wait());
@@ -130,7 +134,9 @@ namespace osu.Game.Tests.Visual.Navigation
IWorkingBeatmap beatmap() => Game.Beatmap.Value;
PushAndConfirm(() => new TestPlaySongSelect());
Screens.Select.SongSelect songSelect = null;
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait());
@@ -257,7 +263,7 @@ namespace osu.Game.Tests.Visual.Navigation
InputManager.ReleaseKey(Key.ControlLeft);
});
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.ID == 1);
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.OnlineID == 1);
AddAssert("Mods overlay still visible", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
}
@@ -278,7 +284,7 @@ namespace osu.Game.Tests.Visual.Navigation
InputManager.ReleaseKey(Key.ControlLeft);
});
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.ID == 1);
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.OnlineID == 1);
AddAssert("Options overlay still visible", () => songSelect.BeatmapOptionsOverlay.State.Value == Visibility.Visible);
}
@@ -200,7 +200,7 @@ namespace osu.Game.Tests.Visual.Online
{
OnlineID = i * 10,
DifficultyName = $"Test #{i}",
RulesetID = Ruleset.Value.ID ?? -1,
RulesetID = Ruleset.Value.OnlineID,
StarRating = 2 + i * 0.1,
OverallDifficulty = 3.5f,
FailTimes = new APIFailTimes
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Online
}
},
Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
Status = BeatmapSetOnlineStatus.Ranked
Status = BeatmapOnlineStatus.Ranked
};
}
@@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.Online
{
new APIBeatmap
{
RulesetID = Ruleset.Value.ID ?? 0,
RulesetID = Ruleset.Value.OnlineID,
DifficultyName = "Test",
StarRating = 6.42,
}
@@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
{
BeatmapInfo = { OnlineID = hasOnlineId ? 1234 : (int?)null }
BeatmapInfo = { OnlineID = hasOnlineId ? 1234 : -1 }
});
AddStep("Run command", () => Add(new NowPlayingCommand()));
@@ -338,7 +338,7 @@ namespace osu.Game.Tests.Visual.Ranking
: base(score, true)
{
Score.BeatmapInfo.OnlineID = 0;
Score.BeatmapInfo.Status = BeatmapSetOnlineStatus.Pending;
Score.BeatmapInfo.Status = BeatmapOnlineStatus.Pending;
}
protected override void LoadComplete()
@@ -0,0 +1,83 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
namespace osu.Game.Tests.Visual.Settings
{
public class TestSceneSettingsNumberBox : OsuTestScene
{
private SettingsNumberBox numberBox;
private OsuTextBox textBox;
[SetUpSteps]
public void SetUpSteps()
{
AddStep("create number box", () => Child = numberBox = new SettingsNumberBox());
AddStep("get inner text box", () => textBox = numberBox.ChildrenOfType<OsuTextBox>().Single());
}
[Test]
public void TestLargeInteger()
{
AddStep("set current to 1,000,000,000", () => numberBox.Current.Value = 1_000_000_000);
AddAssert("text box text is correct", () => textBox.Text == "1000000000");
}
[Test]
public void TestUserInput()
{
inputText("42");
currentValueIs(42);
currentTextIs("42");
inputText(string.Empty);
currentValueIs(null);
currentTextIs(string.Empty);
inputText("555");
currentValueIs(555);
currentTextIs("555");
inputText("-4444");
// attempting to input the minus will raise an input error, the rest will pass through fine.
currentValueIs(4444);
currentTextIs("4444");
// checking the upper bound.
inputText(int.MaxValue.ToString());
currentValueIs(int.MaxValue);
currentTextIs(int.MaxValue.ToString());
inputText(smallestOverflowValue.ToString());
currentValueIs(int.MaxValue);
currentTextIs(int.MaxValue.ToString());
inputText("0");
currentValueIs(0);
currentTextIs("0");
// checking that leading zeroes are stripped.
inputText("00");
currentValueIs(0);
currentTextIs("0");
inputText("01");
currentValueIs(1);
currentTextIs("1");
}
private void inputText(string text) => AddStep($"set textbox text to {text}", () => textBox.Text = text);
private void currentValueIs(int? value) => AddAssert($"current value is {value?.ToString() ?? "null"}", () => numberBox.Current.Value == value);
private void currentTextIs(string value) => AddAssert($"current text is {value}", () => textBox.Text == value);
/// <summary>
/// The smallest number that overflows <see langword="int"/>.
/// </summary>
private static long smallestOverflowValue => 1L + int.MaxValue;
}
}
@@ -3,15 +3,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets;
@@ -19,6 +15,7 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter;
using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelect
@@ -78,9 +75,9 @@ namespace osu.Game.Tests.Visual.SongSelect
{
AddStep("store selection", () => selection = carousel.SelectedBeatmapInfo);
if (isIterating)
AddUntilStep("selection changed", () => carousel.SelectedBeatmapInfo != selection);
AddUntilStep("selection changed", () => !carousel.SelectedBeatmapInfo.Equals(selection));
else
AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo == selection);
AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo.Equals(selection));
}
}
}
@@ -152,7 +149,7 @@ namespace osu.Game.Tests.Visual.SongSelect
const int total_set_count = 200;
for (int i = 0; i < total_set_count; i++)
sets.Add(createTestBeatmapSet(i + 1));
sets.Add(TestResources.CreateTestBeatmapSetInfo());
loadBeatmaps(sets);
@@ -183,7 +180,7 @@ namespace osu.Game.Tests.Visual.SongSelect
const int total_set_count = 20;
for (int i = 0; i < total_set_count; i++)
sets.Add(createTestBeatmapSet(i + 1));
sets.Add(TestResources.CreateTestBeatmapSetInfo(3));
loadBeatmaps(sets);
@@ -228,10 +225,9 @@ namespace osu.Game.Tests.Visual.SongSelect
loadBeatmaps();
// basic filtering
setSelected(1, 1);
AddStep("Filter", () => carousel.Filter(new FilterCriteria { SearchText = "set #3!" }, false));
AddStep("Filter", () => carousel.Filter(new FilterCriteria { SearchText = carousel.BeatmapSets.ElementAt(2).Metadata.Title }, false));
checkVisibleItemCount(diff: false, count: 1);
checkVisibleItemCount(diff: true, count: 3);
waitForSelection(3, 1);
@@ -275,16 +271,20 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestFilterRange()
{
string searchText = null;
loadBeatmaps();
// buffer the selection
setSelected(3, 2);
AddStep("get search text", () => searchText = carousel.SelectedBeatmapSet.Metadata.Title);
setSelected(1, 3);
AddStep("Apply a range filter", () => carousel.Filter(new FilterCriteria
{
SearchText = "#3",
SearchText = searchText,
StarDifficulty = new FilterCriteria.OptionalRange<double>
{
Min = 2,
@@ -327,7 +327,7 @@ namespace osu.Game.Tests.Visual.SongSelect
nextRandom();
AddAssert("ensure repeat", () => selectedSets.Contains(carousel.SelectedBeatmapSet));
AddStep("Add set with 100 difficulties", () => carousel.UpdateBeatmapSet(createTestBeatmapSetWithManyDifficulties(set_count + 1)));
AddStep("Add set with 100 difficulties", () => carousel.UpdateBeatmapSet(TestResources.CreateTestBeatmapSetInfo(100, rulesets.AvailableRulesets.ToArray())));
AddStep("Filter Extra", () => carousel.Filter(new FilterCriteria { SearchText = "Extra 10" }, false));
checkInvisibleDifficultiesUnselectable();
checkInvisibleDifficultiesUnselectable();
@@ -345,18 +345,21 @@ namespace osu.Game.Tests.Visual.SongSelect
{
loadBeatmaps();
AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 1)));
AddStep("Add new set", () => carousel.UpdateBeatmapSet(createTestBeatmapSet(set_count + 2)));
var firstAdded = TestResources.CreateTestBeatmapSetInfo();
var secondAdded = TestResources.CreateTestBeatmapSetInfo();
AddStep("Add new set", () => carousel.UpdateBeatmapSet(firstAdded));
AddStep("Add new set", () => carousel.UpdateBeatmapSet(secondAdded));
checkVisibleItemCount(false, set_count + 2);
AddStep("Remove set", () => carousel.RemoveBeatmapSet(createTestBeatmapSet(set_count + 2)));
AddStep("Remove set", () => carousel.RemoveBeatmapSet(firstAdded));
checkVisibleItemCount(false, set_count + 1);
setSelected(set_count + 1, 1);
AddStep("Remove set", () => carousel.RemoveBeatmapSet(createTestBeatmapSet(set_count + 1)));
AddStep("Remove set", () => carousel.RemoveBeatmapSet(secondAdded));
checkVisibleItemCount(false, set_count);
@@ -372,7 +375,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
sets.Clear();
var rulesetBeatmapSet = createTestBeatmapSet(1);
var rulesetBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1);
var taikoRuleset = rulesets.AvailableRulesets.ElementAt(1);
rulesetBeatmapSet.Beatmaps.ForEach(b =>
{
@@ -397,12 +400,29 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestSorting()
{
loadBeatmaps();
var sets = new List<BeatmapSetInfo>();
const string zzz_string = "zzzzz";
for (int i = 0; i < 20; i++)
{
var set = TestResources.CreateTestBeatmapSetInfo();
if (i == 4)
set.Metadata.Artist = zzz_string;
if (i == 16)
set.Metadata.AuthorString = zzz_string;
sets.Add(set);
}
loadBeatmaps(sets);
AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false));
AddAssert("Check zzzzz is at bottom", () => carousel.BeatmapSets.Last().Metadata.Author.Username == "zzzzz");
AddAssert($"Check {zzz_string} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Author.Username == zzz_string);
AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
AddAssert($"Check #{set_count} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Title.EndsWith($"#{set_count}!", StringComparison.Ordinal));
AddAssert($"Check {zzz_string} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_string);
}
[Test]
@@ -412,19 +432,21 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 0; i < 20; i++)
{
var set = createTestBeatmapSet(i);
var set = TestResources.CreateTestBeatmapSetInfo();
set.Metadata.Artist = "same artist";
set.Metadata.Title = "same title";
sets.Add(set);
}
int idOffset = sets.First().OnlineID ?? 0;
loadBeatmaps(sets);
AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false));
AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.ID == index).All(b => b));
AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == index + idOffset).All(b => b));
AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false));
AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.ID == index).All(b => b));
AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == index + idOffset).All(b => b));
}
[Test]
@@ -434,7 +456,7 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 0; i < 3; i++)
{
var set = createTestBeatmapSet(i);
var set = TestResources.CreateTestBeatmapSetInfo(3);
set.Beatmaps[0].StarRating = 3 - i;
set.Beatmaps[2].StarRating = 6 + i;
sets.Add(set);
@@ -443,12 +465,12 @@ namespace osu.Game.Tests.Visual.SongSelect
loadBeatmaps(sets);
AddStep("Filter to normal", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Normal" }, false));
AddAssert("Check first set at end", () => carousel.BeatmapSets.First() == sets.Last());
AddAssert("Check last set at start", () => carousel.BeatmapSets.Last() == sets.First());
AddAssert("Check first set at end", () => carousel.BeatmapSets.First().Equals(sets.Last()));
AddAssert("Check last set at start", () => carousel.BeatmapSets.Last().Equals(sets.First()));
AddStep("Filter to insane", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Difficulty, SearchText = "Insane" }, false));
AddAssert("Check first set at start", () => carousel.BeatmapSets.First() == sets.First());
AddAssert("Check last set at end", () => carousel.BeatmapSets.Last() == sets.Last());
AddAssert("Check first set at start", () => carousel.BeatmapSets.First().Equals(sets.First()));
AddAssert("Check last set at end", () => carousel.BeatmapSets.Last().Equals(sets.Last()));
}
[Test]
@@ -503,7 +525,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("create hidden set", () =>
{
hidingSet = createTestBeatmapSet(1);
hidingSet = TestResources.CreateTestBeatmapSetInfo(3);
hidingSet.Beatmaps[1].Hidden = true;
hiddenList.Clear();
@@ -550,7 +572,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("add mixed ruleset beatmapset", () =>
{
testMixed = createTestBeatmapSet(set_count + 1);
testMixed = TestResources.CreateTestBeatmapSetInfo(3);
for (int i = 0; i <= 2; i++)
{
@@ -573,7 +595,7 @@ namespace osu.Game.Tests.Visual.SongSelect
BeatmapSetInfo testSingle = null;
AddStep("add single ruleset beatmapset", () =>
{
testSingle = createTestBeatmapSet(set_count + 2);
testSingle = TestResources.CreateTestBeatmapSetInfo(3);
testSingle.Beatmaps.ForEach(b =>
{
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
@@ -593,7 +615,7 @@ namespace osu.Game.Tests.Visual.SongSelect
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
for (int i = 1; i <= 50; i++)
manySets.Add(createTestBeatmapSet(i));
manySets.Add(TestResources.CreateTestBeatmapSetInfo(3));
loadBeatmaps(manySets);
@@ -626,18 +648,11 @@ namespace osu.Game.Tests.Visual.SongSelect
{
for (int i = 0; i < 10; i++)
{
var set = createTestBeatmapSet(i);
foreach (var b in set.Beatmaps)
manySets.Add(TestResources.CreateTestBeatmapSetInfo(3, new[]
{
// all taiko except for first
int ruleset = i > 0 ? 1 : 0;
b.Ruleset = rulesets.GetRuleset(ruleset);
b.RulesetID = ruleset;
}
manySets.Add(set);
rulesets.GetRuleset(i > 0 ? 1 : 0)
}));
}
});
@@ -659,10 +674,10 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("Restore different ruleset filter", () =>
{
carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false);
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID);
eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.OnlineID ?? -1);
});
AddAssert("selection changed", () => carousel.SelectedBeatmapInfo != manySets.First().Beatmaps.First());
AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo.Equals(manySets.First().Beatmaps.First()));
}
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2);
@@ -677,7 +692,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("add mixed difficulty set", () =>
{
set = createTestBeatmapSet(1);
set = TestResources.CreateTestBeatmapSetInfo(1);
set.Beatmaps.Clear();
for (int i = 1; i <= 15; i++)
@@ -729,7 +744,11 @@ namespace osu.Game.Tests.Visual.SongSelect
beatmapSets = new List<BeatmapSetInfo>();
for (int i = 1; i <= (count ?? set_count); i++)
beatmapSets.Add(createTestBeatmapSet(i, randomDifficulties));
{
beatmapSets.Add(randomDifficulties
? TestResources.CreateTestBeatmapSetInfo()
: TestResources.CreateTestBeatmapSetInfo(3));
}
}
carousel.Filter(initialCriteria?.Invoke() ?? new FilterCriteria());
@@ -759,13 +778,13 @@ namespace osu.Game.Tests.Visual.SongSelect
}
private void ensureRandomFetchSuccess() =>
AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet);
AddAssert("ensure prev random fetch worked", () => selectedSets.Peek().Equals(carousel.SelectedBeatmapSet));
private void waitForSelection(int set, int? diff = null) =>
AddUntilStep($"selected is set{set}{(diff.HasValue ? $" diff{diff.Value}" : "")}", () =>
{
if (diff != null)
return carousel.SelectedBeatmapInfo == carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First();
return carousel.SelectedBeatmapInfo?.Equals(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff.Value - 1).First()) == true;
return carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Contains(carousel.SelectedBeatmapInfo);
});
@@ -833,88 +852,6 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("Selection is visible", selectedBeatmapVisible);
}
private BeatmapSetInfo createTestBeatmapSet(int id, bool randomDifficultyCount = false)
{
return new BeatmapSetInfo
{
ID = id,
OnlineID = id,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = $"peppy{id.ToString().PadLeft(6, '0')}",
Title = $"test set #{id}!",
AuthorString = string.Concat(Enumerable.Repeat((char)('z' - Math.Min(25, id - 1)), 5))
},
Beatmaps = getBeatmaps(randomDifficultyCount ? RNG.Next(1, 20) : 3).ToList()
};
}
private IEnumerable<BeatmapInfo> getBeatmaps(int count)
{
int id = 0;
for (int i = 0; i < count; i++)
{
float diff = (float)i / count * 10;
string version = "Normal";
if (diff > 6.6)
version = "Insane";
else if (diff > 3.3)
version = "Hard";
yield return new BeatmapInfo
{
OnlineID = id++ * 10,
DifficultyName = version,
StarRating = diff,
Ruleset = new OsuRuleset().RulesetInfo,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = diff,
}
};
}
}
private BeatmapSetInfo createTestBeatmapSetWithManyDifficulties(int id)
{
var toReturn = new BeatmapSetInfo
{
ID = id,
OnlineID = id,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = $"peppy{id.ToString().PadLeft(6, '0')}",
Title = $"test set #{id}!",
AuthorString = string.Concat(Enumerable.Repeat((char)('z' - Math.Min(25, id - 1)), 5))
},
Beatmaps = new List<BeatmapInfo>(),
};
for (int b = 1; b < 101; b++)
{
toReturn.Beatmaps.Add(new BeatmapInfo
{
OnlineID = b * 10,
Path = $"extra{b}.osu",
DifficultyName = $"Extra {b}",
Ruleset = rulesets.GetRuleset((b - 1) % 4),
StarRating = 2,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
}
});
}
return toReturn;
}
private class TestBeatmapCarousel : BeatmapCarousel
{
public bool PendingFilterTask => PendingFilter != null;
@@ -220,7 +220,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Title = "Verrrrry long Title"
},
DifficultyName = "Verrrrrrrrrrrrrrrrrrrrrrrrrrrrry long Version",
Status = BeatmapSetOnlineStatus.Graveyard,
Status = BeatmapOnlineStatus.Graveyard,
},
};
}
@@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.SongSelect
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory, Scheduler));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
return dependencies;
}
@@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.SongSelect
[Test]
public void TestBeatmapStates()
{
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
foreach (BeatmapOnlineStatus status in Enum.GetValues(typeof(BeatmapOnlineStatus)))
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
}
@@ -384,7 +384,7 @@ namespace osu.Game.Tests.Visual.SongSelect
};
}
private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
private void showBeatmapWithStatus(BeatmapOnlineStatus status)
{
leaderboard.BeatmapInfo = new BeatmapInfo
{
@@ -16,6 +16,7 @@ using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
using osu.Game.Tests.Resources;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.SongSelect
@@ -32,7 +33,7 @@ namespace osu.Game.Tests.Visual.SongSelect
switch (req)
{
case GetUserRequest userRequest:
userRequest.TriggerSuccess(getUser(userRequest.Ruleset.ID));
userRequest.TriggerSuccess(getUser(userRequest.Ruleset.OnlineID));
return true;
}
@@ -89,7 +90,7 @@ namespace osu.Game.Tests.Visual.SongSelect
for (int i = 0; i < import_count; ++i)
{
beatmapSets.Add(importBeatmapSet(i, Enumerable.Repeat(new OsuRuleset().RulesetInfo, 5)));
beatmapSets.Add(importBeatmapSet(Enumerable.Repeat(new OsuRuleset().RulesetInfo, 5)));
}
});
@@ -103,9 +104,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
BeatmapSetInfo catchSet = null, mixedSet = null;
AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(1, new[] { new CatchRuleset().RulesetInfo }));
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(new[] { new CatchRuleset().RulesetInfo }));
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { catchSet, mixedSet }));
@@ -121,9 +121,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
BeatmapSetInfo osuSet = null, mixedSet = null;
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(new[] { new OsuRuleset().RulesetInfo }));
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
@@ -139,9 +138,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
BeatmapSetInfo osuSet = null, mixedSet = null;
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo }));
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(new[] { new OsuRuleset().RulesetInfo }));
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo }));
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
@@ -157,8 +155,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
BeatmapSetInfo osuSet = null, maniaSet = null;
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(2, Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10)));
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(new[] { new OsuRuleset().RulesetInfo }));
AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10)));
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, maniaSet }));
@@ -169,30 +167,19 @@ namespace osu.Game.Tests.Visual.SongSelect
presentAndConfirm(() => maniaSet, 5);
}
private BeatmapSetInfo importBeatmapSet(int importID, IEnumerable<RulesetInfo> difficultyRulesets)
private BeatmapSetInfo importBeatmapSet(IEnumerable<RulesetInfo> difficultyRulesets)
{
var metadata = new BeatmapMetadata
{
Artist = "SomeArtist",
AuthorString = "SomeAuthor",
Title = $"import {importID}"
};
var rulesets = difficultyRulesets.ToArray();
var beatmapSet = new BeatmapSetInfo
var beatmapSet = TestResources.CreateTestBeatmapSetInfo(rulesets.Length, rulesets);
for (int i = 0; i < rulesets.Length; i++)
{
Hash = Guid.NewGuid().ToString(),
OnlineID = importID,
Metadata = metadata,
Beatmaps = difficultyRulesets.Select((ruleset, difficultyIndex) => new BeatmapInfo
{
OnlineID = importID * 1024 + difficultyIndex,
Metadata = metadata,
BaseDifficulty = new BeatmapDifficulty(),
Ruleset = ruleset,
StarRating = difficultyIndex + 1,
DifficultyName = $"SR{difficultyIndex + 1}"
}).ToList()
};
var beatmap = beatmapSet.Beatmaps[i];
beatmap.StarRating = i + 1;
beatmap.DifficultyName = $"SR{i + 1}";
}
return Game.BeatmapManager.Import(beatmapSet).Result.Value;
}
@@ -3,15 +3,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Utils;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
@@ -31,6 +27,7 @@ using osu.Game.Screens.Play;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter;
using osu.Game.Tests.Resources;
using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelect
@@ -148,7 +145,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select next and enter", () =>
{
InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmap>()
.First(b => ((CarouselBeatmap)b.Item).BeatmapInfo != songSelect.Carousel.SelectedBeatmapInfo));
.First(b => !((CarouselBeatmap)b.Item).BeatmapInfo.Equals(songSelect.Carousel.SelectedBeatmapInfo)));
InputManager.Click(MouseButton.Left);
@@ -175,7 +172,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("select next and enter", () =>
{
InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmap>()
.First(b => ((CarouselBeatmap)b.Item).BeatmapInfo != songSelect.Carousel.SelectedBeatmapInfo));
.First(b => !((CarouselBeatmap)b.Item).BeatmapInfo.Equals(songSelect.Carousel.SelectedBeatmapInfo)));
InputManager.PressButton(MouseButton.Left);
@@ -258,8 +255,8 @@ namespace osu.Game.Tests.Visual.SongSelect
{
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets)).Wait();
});
}
else
@@ -354,7 +351,7 @@ namespace osu.Game.Tests.Visual.SongSelect
target = manager.GetAllUsableBeatmapSets()
.Last(b => b.Beatmaps.Any(bi => bi.RulesetID == 0)).Beatmaps.Last();
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == 0);
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0);
Beatmap.Value = manager.GetWorkingBeatmap(target);
});
@@ -385,12 +382,12 @@ namespace osu.Game.Tests.Visual.SongSelect
.Last(b => b.Beatmaps.Any(bi => bi.RulesetID == 0)).Beatmaps.Last();
Beatmap.Value = manager.GetWorkingBeatmap(target);
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == 0);
Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0);
});
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target));
AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0);
AddUntilStep("has correct ruleset", () => Ruleset.Value.OnlineID == 0);
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target));
@@ -505,7 +502,7 @@ namespace osu.Game.Tests.Visual.SongSelect
// special case for converts checked here.
return selectedPanel.ChildrenOfType<FilterableDifficultyIcon>().All(i =>
i.IsFiltered || i.Item.BeatmapInfo.Ruleset.ID == targetRuleset || i.Item.BeatmapInfo.Ruleset.ID == 0);
i.IsFiltered || i.Item.BeatmapInfo.Ruleset.OnlineID == targetRuleset || i.Item.BeatmapInfo.Ruleset.OnlineID == 0);
});
AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
@@ -644,7 +641,7 @@ namespace osu.Game.Tests.Visual.SongSelect
InputManager.Click(MouseButton.Left);
});
AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmapInfo == filteredBeatmap);
AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(filteredBeatmap));
}
[Test]
@@ -665,8 +662,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).Wait();
});
int previousSetID = 0;
@@ -676,11 +673,11 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("record set ID", () => previousSetID = ((IBeatmapSetInfo)Beatmap.Value.BeatmapSetInfo).OnlineID);
AddAssert("selection changed once", () => changeCount == 1);
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
AddAssert("Check ruleset is osu!", () => Ruleset.Value.OnlineID == 0);
changeRuleset(3);
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.OnlineID == 3);
AddUntilStep("selection changed", () => changeCount > 1);
@@ -705,8 +702,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import multi-ruleset map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)).Wait();
});
DrawableCarouselBeatmapSet set = null;
@@ -720,11 +717,11 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("Find an icon for different ruleset", () =>
{
difficultyIcon = set.ChildrenOfType<FilterableDifficultyIcon>()
.FirstOrDefault(icon => icon.Item.BeatmapInfo.Ruleset.ID == 3);
.FirstOrDefault(icon => icon.Item.BeatmapInfo.Ruleset.OnlineID == 3);
return difficultyIcon != null;
});
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
AddAssert("Check ruleset is osu!", () => Ruleset.Value.OnlineID == 0);
int previousSetID = 0;
@@ -737,7 +734,7 @@ namespace osu.Game.Tests.Visual.SongSelect
InputManager.Click(MouseButton.Left);
});
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.OnlineID == 3);
AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet.OnlineID == previousSetID);
AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3);
@@ -754,8 +751,8 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("import huge difficulty count map", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
imported = manager.Import(createTestBeatmapSet(usableRulesets, 50)).Result.Value;
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
imported = manager.Import(TestResources.CreateTestBeatmapSetInfo(50, usableRulesets)).Result.Value;
});
AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First()));
@@ -771,10 +768,10 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("Find group icon for different ruleset", () =>
{
return (groupIcon = set.ChildrenOfType<FilterableGroupedDifficultyIcon>()
.FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.ID == 3)) != null;
.FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.OnlineID == 3)) != null;
});
AddAssert("Check ruleset is osu!", () => Ruleset.Value.ID == 0);
AddAssert("Check ruleset is osu!", () => Ruleset.Value.OnlineID == 0);
AddStep("Click on group", () =>
{
@@ -783,7 +780,7 @@ namespace osu.Game.Tests.Visual.SongSelect
InputManager.Click(MouseButton.Left);
});
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.OnlineID == 3);
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(groupIcon.Items.First().BeatmapInfo));
}
@@ -817,7 +814,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
}
[Test]
@@ -849,7 +846,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap()));
AddAssert("check ruleset is correct for score", () => Ruleset.Value.ID == 0);
AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0);
}
private void waitForInitialSelection()
@@ -858,7 +855,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("wait for difficulty panels visible", () => songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmap>().Any());
}
private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info);
private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.IndexOf(info);
private int getCurrentBeatmapIndex() => getBeatmapIndex(songSelect.Carousel.SelectedBeatmapSet, songSelect.Carousel.SelectedBeatmapInfo);
@@ -869,18 +866,14 @@ namespace osu.Game.Tests.Visual.SongSelect
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
private static int importId;
private int getImportId() => ++importId;
private void importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray())).Wait();
private void checkMusicPlaying(bool playing) =>
AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing);
private void changeMods(params Mod[] mods) => AddStep($"change mods to {string.Join(", ", mods.Select(m => m.Acronym))}", () => SelectedMods.Value = mods);
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.ID == id));
private void changeRuleset(int id) => AddStep($"change ruleset to {id}", () => Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == id));
private void createSongSelect()
{
@@ -893,59 +886,13 @@ namespace osu.Game.Tests.Visual.SongSelect
{
AddStep("import test maps", () =>
{
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.ID != 2).ToArray();
var usableRulesets = rulesets.AvailableRulesets.Where(r => r.OnlineID != 2).ToArray();
for (int i = 0; i < 100; i += 10)
manager.Import(createTestBeatmapSet(usableRulesets)).Wait();
manager.Import(TestResources.CreateTestBeatmapSetInfo(rulesets: usableRulesets)).Wait();
});
}
private BeatmapSetInfo createTestBeatmapSet(RulesetInfo[] rulesets, int countPerRuleset = 6)
{
int j = 0;
RulesetInfo getRuleset() => rulesets[j++ % rulesets.Length];
int setId = getImportId();
var beatmaps = new List<BeatmapInfo>();
for (int i = 0; i < countPerRuleset; i++)
{
int beatmapId = setId * 1000 + i;
int length = RNG.Next(30000, 200000);
double bpm = RNG.NextSingle(80, 200);
beatmaps.Add(new BeatmapInfo
{
Ruleset = getRuleset(),
OnlineID = beatmapId,
DifficultyName = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
Length = length,
BPM = bpm,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
},
});
}
return new BeatmapSetInfo
{
OnlineID = setId,
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
Metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
Title = $"Some Song (set id {setId}, max bpm {beatmaps.Max(b => b.BPM):0.#})",
AuthorString = "Some Guy " + RNG.Next(0, 9),
},
Beatmaps = beatmaps,
DateAdded = DateTimeOffset.UtcNow,
};
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
@@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.UserInterface
dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory, Scheduler));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, ContextFactory, Scheduler));
beatmapInfo = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).Result.Value.Beatmaps[0];
@@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestLabelledEnumDropdown()
=> AddStep(@"create dropdown", () => Child = new LabelledEnumDropdown<BeatmapSetOnlineStatus>
=> AddStep(@"create dropdown", () => Child = new LabelledEnumDropdown<BeatmapOnlineStatus>
{
Label = @"Beatmap status",
Description = @"This is a description"
@@ -378,9 +378,9 @@ namespace osu.Game.Tests.Visual.UserInterface
});
}
private void changeRuleset(int? id)
private void changeRuleset(int? onlineId)
{
AddStep($"change ruleset to {(id?.ToString() ?? "none")}", () => { Ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(r => r.ID == id); });
AddStep($"change ruleset to {(onlineId?.ToString() ?? "none")}", () => { Ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault(r => r.OnlineID == onlineId); });
waitForLoad();
}
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public void SetUp() => Schedule(() =>
{
SelectedMods.Value = Array.Empty<Mod>();
Ruleset.Value = new TestRulesetInfo();
Ruleset.Value = CreateTestRulesetInfo();
});
[Test]
@@ -170,40 +170,32 @@ namespace osu.Game.Tests.Visual.UserInterface
ModSettingsContainer.Parent.Width = newWidth;
}
public class TestRulesetInfo : RulesetInfo
public static RulesetInfo CreateTestRulesetInfo() => new TestCustomisableModRuleset().RulesetInfo;
public class TestCustomisableModRuleset : Ruleset
{
public override Ruleset CreateInstance() => new TestCustomisableModRuleset();
public TestRulesetInfo()
public override IEnumerable<Mod> GetModsFor(ModType type)
{
Available = true;
}
public class TestCustomisableModRuleset : Ruleset
{
public override IEnumerable<Mod> GetModsFor(ModType type)
if (type == ModType.Conversion)
{
if (type == ModType.Conversion)
return new Mod[]
{
return new Mod[]
{
new TestModCustomisable1(),
new TestModCustomisable2()
};
}
return Array.Empty<Mod>();
new TestModCustomisable1(),
new TestModCustomisable2()
};
}
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
public override string Description { get; } = "test";
public override string ShortName { get; } = "tst";
return Array.Empty<Mod>();
}
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException();
public override string Description { get; } = "test";
public override string ShortName { get; } = "tst";
}
private class TestModCustomisable1 : TestModCustomisable
@@ -10,7 +10,7 @@ namespace osu.Game.Tests.Visual.UserInterface
public class TestSceneOsuDropdown : ThemeComparisonTestScene
{
protected override Drawable CreateContent() =>
new OsuEnumDropdown<BeatmapSetOnlineStatus>
new OsuEnumDropdown<BeatmapOnlineStatus>
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -1,16 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays.Music;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Input;
@@ -22,6 +22,8 @@ namespace osu.Game.Tests.Visual.UserInterface
private PlaylistOverlay playlistOverlay;
private BeatmapSetInfo first;
[SetUp]
public void Setup() => Schedule(() =>
{
@@ -43,19 +45,11 @@ namespace osu.Game.Tests.Visual.UserInterface
for (int i = 0; i < 100; i++)
{
beatmapSets.Add(new BeatmapSetInfo
{
Metadata = new BeatmapMetadata
{
// Create random metadata, then we can check if sorting works based on these
Artist = "Some Artist " + RNG.Next(0, 9),
Title = $"Some Song {i + 1}",
AuthorString = "Some Guy " + RNG.Next(0, 9),
},
DateAdded = DateTimeOffset.UtcNow,
});
beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo());
}
first = beatmapSets.First();
playlistOverlay.BeatmapSets.BindTo(beatmapSets);
});
@@ -66,7 +60,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("hold 1st item handle", () =>
{
var handle = this.ChildrenOfType<PlaylistItem.PlaylistItemHandle>().First();
var handle = this.ChildrenOfType<OsuRearrangeableListItem<BeatmapSetInfo>.PlaylistItemHandle>().First();
InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre);
InputManager.PressButton(MouseButton.Left);
});
@@ -77,7 +71,7 @@ namespace osu.Game.Tests.Visual.UserInterface
InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.Centre);
});
AddAssert("song 1 is 5th", () => beatmapSets[4].Metadata.Title == "Some Song 1");
AddAssert("song 1 is 5th", () => beatmapSets[4] == first);
AddStep("release handle", () => InputManager.ReleaseButton(MouseButton.Left));
}
@@ -42,7 +42,12 @@ namespace osu.Game.Tournament.Tests.Components
private void success(APIBeatmap beatmap)
{
var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().AllMods;
var ruleset = rulesets.GetRuleset(Ladder.Ruleset.Value.OnlineID);
if (ruleset == null)
return;
var mods = ruleset.CreateInstance().AllMods;
foreach (var mod in mods)
{
@@ -38,7 +38,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
{
using (HeadlessGameHost host = new HeadlessGameHost(nameof(TestCustomDirectory))) // don't use clean run as we are writing a config file.
{
string osuDesktopStorage = basePath(nameof(TestCustomDirectory));
string osuDesktopStorage = PrepareBasePath(nameof(TestCustomDirectory));
const string custom_tournament = "custom";
// need access before the game has constructed its own storage yet.
@@ -60,6 +60,15 @@ namespace osu.Game.Tournament.Tests.NonVisual
finally
{
host.Exit();
try
{
if (Directory.Exists(osuDesktopStorage))
Directory.Delete(osuDesktopStorage, true);
}
catch
{
}
}
}
}
@@ -69,7 +78,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
{
using (HeadlessGameHost host = new HeadlessGameHost(nameof(TestMigration))) // don't use clean run as we are writing test files for migration.
{
string osuRoot = basePath(nameof(TestMigration));
string osuRoot = PrepareBasePath(nameof(TestMigration));
string configFile = Path.Combine(osuRoot, "tournament.ini");
if (File.Exists(configFile))
@@ -136,18 +145,29 @@ namespace osu.Game.Tournament.Tests.NonVisual
}
finally
{
host.Exit();
try
{
host.Storage.Delete("tournament.ini");
host.Storage.DeleteDirectory("tournaments");
if (Directory.Exists(osuRoot))
Directory.Delete(osuRoot, true);
}
catch
{
}
catch { }
host.Exit();
}
}
}
private string basePath(string testInstance) => Path.Combine(RuntimeInfo.StartupDirectory, "headless", testInstance);
public static string PrepareBasePath(string testInstance)
{
string basePath = Path.Combine(RuntimeInfo.StartupDirectory, "headless", testInstance);
// manually clean before starting in case there are left-over files at the test site.
if (Directory.Exists(basePath))
Directory.Delete(basePath, true);
return basePath;
}
}
}
@@ -3,7 +3,6 @@
using System.IO;
using NUnit.Framework;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Platform;
using osu.Game.Tournament.IO;
@@ -20,7 +19,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
// don't use clean run because files are being written before osu! launches.
using (HeadlessGameHost host = new HeadlessGameHost(nameof(CheckIPCLocation)))
{
string basePath = Path.Combine(RuntimeInfo.StartupDirectory, "headless", nameof(CheckIPCLocation));
string basePath = CustomTourneyDirectoryTest.PrepareBasePath(nameof(CheckIPCLocation));
// Set up a fake IPC client for the IPC Storage to switch to.
string testStableInstallDirectory = Path.Combine(basePath, "stable-ce");
@@ -42,9 +41,16 @@ namespace osu.Game.Tournament.Tests.NonVisual
}
finally
{
host.Storage.DeleteDirectory(testStableInstallDirectory);
host.Storage.DeleteDirectory("tournaments");
host.Exit();
try
{
if (Directory.Exists(basePath))
Directory.Delete(basePath, true);
}
catch
{
}
}
}
}
@@ -20,7 +20,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
return tournament;
}
public static void WaitForOrAssert(Func<bool> result, string failureMessage, int timeout = 90000)
public static void WaitForOrAssert(Func<bool> result, string failureMessage, int timeout = 30000)
{
Task task = Task.Run(() =>
{
+1 -1
View File
@@ -127,7 +127,7 @@ namespace osu.Game.Tournament.Components
(string heading, string content)[] stats;
switch (ruleset.Value.ID)
switch (ruleset.Value.OnlineID)
{
default:
stats = new (string heading, string content)[]
+3 -1
View File
@@ -105,7 +105,9 @@ namespace osu.Game.Audio
protected override void LoadComplete()
{
base.LoadComplete();
Logger.Log($"A {nameof(PreviewTrack)} was created without a containing {nameof(IPreviewTrackOwner)}. An owner should be added for correct behaviour.");
if (Owner == null)
Logger.Log($"A {nameof(PreviewTrack)} was created without a containing {nameof(IPreviewTrackOwner)}. An owner should be added for correct behaviour.");
}
protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineID}.mp3");
+3 -3
View File
@@ -340,8 +340,8 @@ namespace osu.Game.Beatmaps
}
public bool Equals(DifficultyCacheLookup other)
=> BeatmapInfo.ID == other.BeatmapInfo.ID
&& Ruleset.ID == other.Ruleset.ID
=> BeatmapInfo.Equals(other.BeatmapInfo)
&& Ruleset.Equals(other.Ruleset)
&& OrderedMods.SequenceEqual(other.OrderedMods);
public override int GetHashCode()
@@ -349,7 +349,7 @@ namespace osu.Game.Beatmaps
var hashCode = new HashCode();
hashCode.Add(BeatmapInfo.ID);
hashCode.Add(Ruleset.ID);
hashCode.Add(Ruleset.ShortName);
foreach (var mod in OrderedMods)
hashCode.Add(mod);
+1 -24
View File
@@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Testing;
using osu.Game.Database;
@@ -36,7 +35,7 @@ namespace osu.Game.Beatmaps
[JsonIgnore]
public int BeatmapSetInfoID { get; set; }
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None;
[Required]
public BeatmapSetInfo BeatmapSet { get; set; }
@@ -104,28 +103,6 @@ namespace osu.Game.Beatmaps
/// </summary>
public int CountdownOffset { get; set; }
// Editor
// This bookmarks stuff is necessary because DB doesn't know how to store int[]
[JsonIgnore]
public string StoredBookmarks
{
get => string.Join(',', Bookmarks);
set
{
if (string.IsNullOrEmpty(value))
{
Bookmarks = Array.Empty<int>();
return;
}
Bookmarks = value.Split(',').Select(v =>
{
bool result = int.TryParse(v, out int val);
return new { result, val };
}).Where(p => p.result).Select(p => p.val).ToArray();
}
}
[NotMapped]
public int[] Bookmarks { get; set; } = Array.Empty<int>();
+4 -53
View File
@@ -10,7 +10,6 @@ using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Audio;
using osu.Framework.Audio.Mixing;
using osu.Framework.Audio.Track;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
@@ -30,24 +29,22 @@ namespace osu.Game.Beatmaps
/// Handles general operations related to global beatmap management.
/// </summary>
[ExcludeFromDynamicCompile]
public class BeatmapManager : IModelDownloader<IBeatmapSetInfo>, IModelManager<BeatmapSetInfo>, IModelFileManager<BeatmapSetInfo, BeatmapSetFileInfo>, IModelImporter<BeatmapSetInfo>, IWorkingBeatmapCache, IDisposable
public class BeatmapManager : IModelManager<BeatmapSetInfo>, IModelFileManager<BeatmapSetInfo, BeatmapSetFileInfo>, IModelImporter<BeatmapSetInfo>, IWorkingBeatmapCache, IDisposable
{
public ITrackStore BeatmapTrackStore { get; }
private readonly BeatmapModelManager beatmapModelManager;
private readonly BeatmapModelDownloader beatmapModelDownloader;
private readonly WorkingBeatmapCache workingBeatmapCache;
private readonly BeatmapOnlineLookupQueue onlineBeatmapLookupQueue;
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore<byte[]> gameResources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false, AudioMixer mainTrackMixer = null)
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, [NotNull] AudioManager audioManager, IResourceStore<byte[]> gameResources, GameHost host = null, WorkingBeatmap defaultBeatmap = null, bool performOnlineLookups = false)
{
var userResources = new FileStore(contextFactory, storage).Store;
BeatmapTrackStore = audioManager.GetTrackStore(userResources);
beatmapModelManager = CreateBeatmapModelManager(storage, contextFactory, rulesets, api, host);
beatmapModelDownloader = CreateBeatmapModelDownloader(beatmapModelManager, api, host);
workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
workingBeatmapCache.BeatmapManager = beatmapModelManager;
@@ -60,11 +57,6 @@ namespace osu.Game.Beatmaps
}
}
protected virtual BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> modelManager, IAPIProvider api, GameHost host)
{
return new BeatmapModelDownloader(modelManager, api, host);
}
protected virtual WorkingBeatmapCache CreateWorkingBeatmapCache(AudioManager audioManager, IResourceStore<byte[]> resources, IResourceStore<byte[]> storage, WorkingBeatmap defaultBeatmap, GameHost host)
{
return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host);
@@ -86,7 +78,7 @@ namespace osu.Game.Beatmaps
var set = new BeatmapSetInfo
{
Metadata = metadata,
Beatmaps = new List<BeatmapInfo>
Beatmaps =
{
new BeatmapInfo
{
@@ -186,11 +178,7 @@ namespace osu.Game.Beatmaps
/// </summary>
public Action<Notification> PostNotification
{
set
{
beatmapModelManager.PostNotification = value;
beatmapModelDownloader.PostNotification = value;
}
set => beatmapModelManager.PostNotification = value;
}
/// <summary>
@@ -226,21 +214,6 @@ namespace osu.Game.Beatmaps
remove => beatmapModelManager.ItemRemoved -= value;
}
public Task ImportFromStableAsync(StableStorage stableStorage)
{
return beatmapModelManager.ImportFromStableAsync(stableStorage);
}
public void Export(BeatmapSetInfo item)
{
beatmapModelManager.Export(item);
}
public void ExportModelTo(BeatmapSetInfo model, Stream outputStream)
{
beatmapModelManager.ExportModelTo(model, outputStream);
}
public void Update(BeatmapSetInfo item)
{
beatmapModelManager.Update(item);
@@ -268,28 +241,6 @@ namespace osu.Game.Beatmaps
#endregion
#region Implementation of IModelDownloader<BeatmapSetInfo>
public event Action<ArchiveDownloadRequest<IBeatmapSetInfo>> DownloadBegan
{
add => beatmapModelDownloader.DownloadBegan += value;
remove => beatmapModelDownloader.DownloadBegan -= value;
}
public event Action<ArchiveDownloadRequest<IBeatmapSetInfo>> DownloadFailed
{
add => beatmapModelDownloader.DownloadFailed += value;
remove => beatmapModelDownloader.DownloadFailed -= value;
}
public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false) =>
beatmapModelDownloader.Download(model, minimiseDownloadSize);
public ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model) =>
beatmapModelDownloader.GetExistingDownload(model);
#endregion
#region Implementation of ICanAcceptFiles
public Task Import(params string[] paths)
+2 -3
View File
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
@@ -16,8 +15,8 @@ namespace osu.Game.Beatmaps
public override ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model)
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
public BeatmapModelDownloader(IModelImporter<BeatmapSetInfo> beatmapImporter, IAPIProvider api, GameHost host = null)
: base(beatmapImporter, api, host)
public BeatmapModelDownloader(IModelImporter<BeatmapSetInfo> beatmapImporter, IAPIProvider api)
: base(beatmapImporter, api)
{
}
}
+4 -9
View File
@@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps
/// Handles ef-core storage of beatmaps.
/// </summary>
[ExcludeFromDynamicCompile]
public class BeatmapModelManager : ArchiveModelManager<BeatmapSetInfo, BeatmapSetFileInfo>, IBeatmapModelManager
public class BeatmapModelManager : ArchiveModelManager<BeatmapSetInfo, BeatmapSetFileInfo>
{
/// <summary>
/// Fired when a single difficulty has been hidden.
@@ -58,10 +58,6 @@ namespace osu.Game.Beatmaps
protected override string[] HashableFileTypes => new[] { ".osu" };
protected override string ImportFromStablePath => ".";
protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage();
private readonly BeatmapStore beatmaps;
private readonly RulesetStore rulesets;
@@ -82,7 +78,7 @@ namespace osu.Game.Beatmaps
protected override async Task Populate(BeatmapSetInfo beatmapSet, ArchiveReader archive, CancellationToken cancellationToken = default)
{
if (archive != null)
beatmapSet.Beatmaps = createBeatmapDifficulties(beatmapSet.Files);
beatmapSet.Beatmaps.AddRange(createBeatmapDifficulties(beatmapSet.Files));
foreach (BeatmapInfo b in beatmapSet.Beatmaps)
{
@@ -208,7 +204,7 @@ namespace osu.Game.Beatmaps
using (ContextFactory.GetForWrite())
{
beatmapInfo = setInfo.Beatmaps.Single(b => b.ID == beatmapInfo.ID);
beatmapInfo = setInfo.Beatmaps.Single(b => b.Equals(beatmapInfo));
var metadata = beatmapInfo.Metadata ?? setInfo.Metadata;
@@ -216,7 +212,7 @@ namespace osu.Game.Beatmaps
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.
beatmapInfo.Path = GetValidFilename($"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu");
beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename();
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
@@ -370,7 +366,6 @@ namespace osu.Game.Beatmaps
return new BeatmapSetInfo
{
OnlineID = beatmap.BeatmapInfo.BeatmapSet?.OnlineID,
Beatmaps = new List<BeatmapInfo>(),
Metadata = beatmap.Metadata,
DateAdded = DateTimeOffset.UtcNow
};
@@ -83,7 +83,7 @@ namespace osu.Game.Beatmaps
if (res != null)
{
beatmapInfo.Status = res.Status;
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapSetOnlineStatus.None;
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
beatmapInfo.OnlineID = res.OnlineID;
@@ -182,7 +182,7 @@ namespace osu.Game.Beatmaps
{
if (reader.Read())
{
var status = (BeatmapSetOnlineStatus)reader.GetByte(2);
var status = (BeatmapOnlineStatus)reader.GetByte(2);
beatmapInfo.Status = status;
beatmapInfo.BeatmapSet.Status = status;
@@ -6,7 +6,7 @@ using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps
{
public enum BeatmapSetOnlineStatus
public enum BeatmapOnlineStatus
{
None = -3,
@@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps
public static class BeatmapSetOnlineStatusExtensions
{
public static bool GrantsPerformancePoints(this BeatmapSetOnlineStatus status)
=> status == BeatmapSetOnlineStatus.Ranked || status == BeatmapSetOnlineStatus.Approved;
public static bool GrantsPerformancePoints(this BeatmapOnlineStatus status)
=> status == BeatmapOnlineStatus.Ranked || status == BeatmapOnlineStatus.Approved;
}
}
+14 -10
View File
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Extensions;
@@ -30,27 +31,30 @@ namespace osu.Game.Beatmaps
public BeatmapMetadata Metadata { get; set; }
public List<BeatmapInfo> Beatmaps { get; set; }
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
[NotNull]
public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>();
public List<BeatmapInfo> Beatmaps { get; } = new List<BeatmapInfo>();
public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None;
public List<BeatmapSetFileInfo> Files { get; } = new List<BeatmapSetFileInfo>();
/// <summary>
/// The maximum star difficulty of all beatmaps in this set.
/// </summary>
public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarRating) ?? 0;
[JsonIgnore]
public double MaxStarDifficulty => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.StarRating);
/// <summary>
/// The maximum playable length in milliseconds of all beatmaps in this set.
/// </summary>
public double MaxLength => Beatmaps?.Max(b => b.Length) ?? 0;
[JsonIgnore]
public double MaxLength => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.Length);
/// <summary>
/// The maximum BPM of all beatmaps in this set.
/// </summary>
public double MaxBPM => Beatmaps?.Max(b => b.BPM) ?? 0;
[JsonIgnore]
public double MaxBPM => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.BPM);
[NotMapped]
public bool DeletePending { get; set; }
@@ -89,9 +93,9 @@ namespace osu.Game.Beatmaps
#region Implementation of IBeatmapSetInfo
IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata;
IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata ?? Beatmaps.FirstOrDefault()?.Metadata ?? new BeatmapMetadata();
IEnumerable<IBeatmapInfo> IBeatmapSetInfo.Beatmaps => Beatmaps;
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => Files;
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
#endregion
}
+1 -1
View File
@@ -83,7 +83,7 @@ namespace osu.Game.Beatmaps
requestedUserId = api.LocalUser.Value.Id;
// only query API for built-in rulesets
rulesets.AvailableRulesets.Where(ruleset => ruleset.ID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID).ForEach(rulesetInfo =>
rulesets.AvailableRulesets.Where(ruleset => ruleset.OnlineID >= 0 && ruleset.OnlineID <= ILegacyRuleset.MAX_LEGACY_RULESET_ID).ForEach(rulesetInfo =>
{
var req = new GetUserRequest(api.LocalUser.Value.Id, rulesetInfo);
@@ -18,9 +18,9 @@ namespace osu.Game.Beatmaps.Drawables
{
public class BeatmapSetOnlineStatusPill : CircularContainer
{
private BeatmapSetOnlineStatus status;
private BeatmapOnlineStatus status;
public BeatmapSetOnlineStatus Status
public BeatmapOnlineStatus Status
{
get => status;
set
@@ -75,7 +75,7 @@ namespace osu.Game.Beatmaps.Drawables
},
};
Status = BeatmapSetOnlineStatus.None;
Status = BeatmapOnlineStatus.None;
TextPadding = new MarginPadding { Horizontal = 5, Bottom = 1 };
}
@@ -87,14 +87,14 @@ namespace osu.Game.Beatmaps.Drawables
private void updateState()
{
Alpha = Status == BeatmapSetOnlineStatus.None ? 0 : 1;
Alpha = Status == BeatmapOnlineStatus.None ? 0 : 1;
statusText.Text = Status.GetLocalisableDescription().ToUpper();
if (colourProvider != null)
statusText.Colour = status == BeatmapSetOnlineStatus.Graveyard ? colourProvider.Background1 : colourProvider.Background3;
statusText.Colour = status == BeatmapOnlineStatus.Graveyard ? colourProvider.Background1 : colourProvider.Background3;
else
statusText.Colour = status == BeatmapSetOnlineStatus.Graveyard ? colours.GreySeafoamLight : Color4.Black;
statusText.Colour = status == BeatmapOnlineStatus.Graveyard ? colours.GreySeafoamLight : Color4.Black;
background.Colour = OsuColour.ForBeatmapSetOnlineStatus(Status) ?? colourProvider?.Light1 ?? colours.GreySeafoamLighter;
}
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable enable
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -23,7 +25,6 @@ using osu.Game.Overlays.BeatmapSet;
using osuTK;
using osu.Game.Overlays.BeatmapListing.Panels;
using osu.Game.Resources.Localisation.Web;
using osuTK.Graphics;
using DownloadButton = osu.Game.Beatmaps.Drawables.Cards.Buttons.DownloadButton;
namespace osu.Game.Beatmaps.Drawables.Cards
@@ -42,27 +43,23 @@ namespace osu.Game.Beatmaps.Drawables.Cards
private readonly BeatmapDownloadTracker downloadTracker;
private UpdateableOnlineBeatmapSetCover leftCover;
private FillFlowContainer leftIconArea;
private BeatmapCardThumbnail thumbnail = null!;
private Container rightAreaBackground;
private Container<BeatmapCardIconButton> rightAreaButtons;
private Container rightAreaBackground = null!;
private Container<BeatmapCardIconButton> rightAreaButtons = null!;
private Container mainContent;
private BeatmapCardContentBackground mainContentBackground;
private Container mainContent = null!;
private BeatmapCardContentBackground mainContentBackground = null!;
private FillFlowContainer<BeatmapCardStatistic> statisticsContainer = null!;
private GridContainer titleContainer;
private GridContainer artistContainer;
private FillFlowContainer<BeatmapCardStatistic> statisticsContainer;
private FillFlowContainer idleBottomContent;
private BeatmapCardDownloadProgressBar downloadProgressBar;
private FillFlowContainer idleBottomContent = null!;
private BeatmapCardDownloadProgressBar downloadProgressBar = null!;
[Resolved]
private OsuColour colours { get; set; }
private OsuColour colours { get; set; } = null!;
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
private OverlayColourProvider colourProvider { get; set; } = null!;
public BeatmapCard(APIBeatmapSet beatmapSet)
: base(HoverSampleSet.Submit)
@@ -72,14 +69,18 @@ namespace osu.Game.Beatmaps.Drawables.Cards
downloadTracker = new BeatmapDownloadTracker(beatmapSet);
}
[BackgroundDependencyLoader]
private void load()
[BackgroundDependencyLoader(true)]
private void load(BeatmapSetOverlay? beatmapSetOverlay)
{
Width = width;
Height = height;
CornerRadius = corner_radius;
Masking = true;
FillFlowContainer leftIconArea;
GridContainer titleContainer;
GridContainer artistContainer;
InternalChildren = new Drawable[]
{
downloadTracker,
@@ -98,24 +99,17 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Colour = Colour4.White
},
},
new Container
thumbnail = new BeatmapCardThumbnail(beatmapSet)
{
Name = @"Left (icon) area",
Size = new Vector2(height),
Children = new Drawable[]
Padding = new MarginPadding { Right = corner_radius },
Child = leftIconArea = new FillFlowContainer
{
leftCover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.List)
{
RelativeSizeAxes = Axes.Both,
OnlineInfo = beatmapSet
},
leftIconArea = new FillFlowContainer
{
Margin = new MarginPadding(5),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(1)
}
Margin = new MarginPadding(5),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(1)
}
},
new Container
@@ -319,10 +313,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards
};
if (beatmapSet.HasVideo)
leftIconArea.Add(new IconPill(FontAwesome.Solid.Film));
leftIconArea.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
if (beatmapSet.HasStoryboard)
leftIconArea.Add(new IconPill(FontAwesome.Solid.Image));
leftIconArea.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) });
if (beatmapSet.HasExplicitContent)
{
@@ -343,6 +337,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Margin = new MarginPadding { Left = 5 }
};
}
Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmapSet.OnlineID);
}
protected override void LoadComplete()
@@ -395,10 +391,11 @@ namespace osu.Game.Beatmaps.Drawables.Cards
if (IsHovered)
targetWidth = targetWidth - icon_area_width + corner_radius;
thumbnail.Dimmed.Value = IsHovered;
mainContent.ResizeWidthTo(targetWidth, TRANSITION_DURATION, Easing.OutQuint);
mainContentBackground.Dimmed.Value = IsHovered;
leftCover.FadeColour(IsHovered ? OsuColour.Gray(0.2f) : Color4.White, TRANSITION_DURATION, Easing.OutQuint);
statisticsContainer.FadeTo(IsHovered ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
rightAreaBackground.FadeColour(downloadTracker.State.Value == DownloadState.LocallyAvailable ? colours.Lime0 : colourProvider.Background3, TRANSITION_DURATION, Easing.OutQuint);
@@ -0,0 +1,95 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps.Drawables.Cards.Buttons;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Screens.Ranking.Expanded.Accuracy;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables.Cards
{
public class BeatmapCardThumbnail : Container
{
public BindableBool Dimmed { get; } = new BindableBool();
public new MarginPadding Padding
{
get => foreground.Padding;
set => foreground.Padding = value;
}
private readonly UpdateableOnlineBeatmapSetCover cover;
private readonly Container foreground;
private readonly PlayButton playButton;
private readonly SmoothCircularProgress progress;
private readonly Container content;
protected override Container<Drawable> Content => content;
public BeatmapCardThumbnail(APIBeatmapSet beatmapSetInfo)
{
InternalChildren = new Drawable[]
{
cover = new UpdateableOnlineBeatmapSetCover(BeatmapSetCoverType.List)
{
RelativeSizeAxes = Axes.Both,
OnlineInfo = beatmapSetInfo
},
foreground = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
playButton = new PlayButton(beatmapSetInfo)
{
RelativeSizeAxes = Axes.Both
},
progress = new SmoothCircularProgress
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(50),
InnerRadius = 0.2f
},
content = new Container
{
RelativeSizeAxes = Axes.Both
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
progress.Colour = colourProvider.Highlight1;
}
protected override void LoadComplete()
{
base.LoadComplete();
Dimmed.BindValueChanged(_ => updateState());
playButton.Playing.BindValueChanged(_ => updateState(), true);
((IBindable<double>)progress.Current).BindTo(playButton.Progress);
FinishTransforms(true);
}
private void updateState()
{
bool shouldDim = Dimmed.Value || playButton.Playing.Value;
playButton.FadeTo(shouldDim ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
cover.FadeColour(shouldDim ? OsuColour.Gray(0.2f) : Color4.White, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
}
}
}
@@ -54,6 +54,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
protected readonly SpriteIcon Icon;
protected override Container<Drawable> Content => content;
private readonly Container content;
protected BeatmapCardIconButton()
@@ -61,7 +63,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
Origin = Anchor.Centre;
Anchor = Anchor.Centre;
Child = content = new Container
base.Content.Add(content = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
@@ -75,7 +77,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
Anchor = Anchor.Centre
}
}
};
});
Size = new Vector2(24);
IconSize = 12;
@@ -3,14 +3,17 @@
#nullable enable
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osu.Game.Resources.Localisation.Web;
using osuTK;
namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
@@ -23,13 +26,17 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
private Bindable<bool> preferNoVideo = null!;
private readonly LoadingSpinner spinner;
[Resolved]
private BeatmapManager beatmaps { get; set; } = null!;
private BeatmapModelDownloader beatmaps { get; set; } = null!;
public DownloadButton(APIBeatmapSet beatmapSet)
{
Icon.Icon = FontAwesome.Solid.Download;
Content.Add(spinner = new LoadingSpinner { Size = new Vector2(IconSize) });
this.beatmapSet = beatmapSet;
}
@@ -49,21 +56,44 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
private void updateState()
{
this.FadeTo(state.Value != DownloadState.LocallyAvailable ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
if (beatmapSet.Availability.DownloadDisabled)
switch (state.Value)
{
Enabled.Value = false;
TooltipText = BeatmapsetsStrings.AvailabilityDisabled;
return;
case DownloadState.Downloading:
case DownloadState.Importing:
Action = null;
TooltipText = string.Empty;
spinner.Show();
Icon.Hide();
break;
case DownloadState.LocallyAvailable:
Action = null;
TooltipText = string.Empty;
this.FadeOut(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
break;
case DownloadState.NotDownloaded:
if (beatmapSet.Availability.DownloadDisabled)
{
Enabled.Value = false;
TooltipText = BeatmapsetsStrings.AvailabilityDisabled;
return;
}
Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value);
this.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
spinner.Hide();
Icon.Show();
if (!beatmapSet.HasVideo)
TooltipText = BeatmapsetsStrings.PanelDownloadAll;
else
TooltipText = preferNoVideo.Value ? BeatmapsetsStrings.PanelDownloadNoVideo : BeatmapsetsStrings.PanelDownloadVideo;
break;
default:
throw new InvalidOperationException($"Unknown {nameof(DownloadState)} specified.");
}
if (!beatmapSet.HasVideo)
TooltipText = BeatmapsetsStrings.PanelDownloadAll;
else
TooltipText = preferNoVideo.Value ? BeatmapsetsStrings.PanelDownloadNoVideo : BeatmapsetsStrings.PanelDownloadVideo;
Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value);
}
}
}
@@ -0,0 +1,148 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable enable
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osuTK;
namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
{
public class PlayButton : OsuHoverContainer
{
public IBindable<double> Progress => progress;
private readonly BindableDouble progress = new BindableDouble();
public BindableBool Playing { get; } = new BindableBool();
private readonly IBeatmapSetInfo beatmapSetInfo;
protected override IEnumerable<Drawable> EffectTargets => icon.Yield();
private readonly SpriteIcon icon;
private readonly LoadingSpinner loadingSpinner;
[Resolved]
private PreviewTrackManager previewTrackManager { get; set; } = null!;
private PreviewTrack? previewTrack;
public PlayButton(IBeatmapSetInfo beatmapSetInfo)
{
this.beatmapSetInfo = beatmapSetInfo;
Anchor = Origin = Anchor.Centre;
Children = new Drawable[]
{
icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.Solid.Play,
Size = new Vector2(14)
},
loadingSpinner = new LoadingSpinner
{
Size = new Vector2(14)
}
};
Action = () => Playing.Toggle();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
HoverColour = colours.Yellow;
}
protected override void LoadComplete()
{
base.LoadComplete();
Playing.BindValueChanged(updateState, true);
}
protected override void Update()
{
base.Update();
if (Playing.Value && previewTrack != null && previewTrack.TrackLoaded)
progress.Value = previewTrack.CurrentTime / previewTrack.Length;
else
progress.Value = 0;
}
private void updateState(ValueChangedEvent<bool> playing)
{
icon.Icon = playing.NewValue ? FontAwesome.Solid.Stop : FontAwesome.Solid.Play;
if (!playing.NewValue)
{
stopPreview();
return;
}
if (previewTrack == null)
{
toggleLoading(true);
LoadComponentAsync(previewTrack = previewTrackManager.Get(beatmapSetInfo), onPreviewLoaded);
}
else
tryStartPreview();
}
private void stopPreview()
{
toggleLoading(false);
Playing.Value = false;
previewTrack?.Stop();
}
private void onPreviewLoaded(PreviewTrack loadedPreview)
{
// Make sure that we schedule to after the next audio frame to fix crashes in single-threaded execution.
// See: https://github.com/ppy/osu-framework/issues/4692
Schedule(() =>
{
// another async load might have completed before this one.
// if so, do not make any changes.
if (loadedPreview != previewTrack)
return;
AddInternal(loadedPreview);
toggleLoading(false);
loadedPreview.Stopped += () => Schedule(() => Playing.Value = false);
if (Playing.Value)
tryStartPreview();
});
}
private void tryStartPreview()
{
if (previewTrack?.Start() == false)
Playing.Value = false;
}
private void toggleLoading(bool loading)
{
Enabled.Value = !loading;
icon.FadeTo(loading ? 0 : 1, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
loadingSpinner.State.Value = loading ? Visibility.Visible : Visibility.Hidden;
}
}
}
@@ -41,10 +41,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics
// reference: https://github.com/ppy/osu-web/blob/ef432c11719fd1207bec5f9194b04f0033bdf02c/resources/assets/lib/beatmapset-panel.tsx#L36-L44
switch (beatmapSetInfo.Status)
{
case BeatmapSetOnlineStatus.Ranked:
case BeatmapSetOnlineStatus.Approved:
case BeatmapSetOnlineStatus.Loved:
case BeatmapSetOnlineStatus.Qualified:
case BeatmapOnlineStatus.Ranked:
case BeatmapOnlineStatus.Approved:
case BeatmapOnlineStatus.Loved:
case BeatmapOnlineStatus.Qualified:
return beatmapSetInfo.Ranked;
default:
@@ -117,7 +117,7 @@ namespace osu.Game.Beatmaps.Drawables
Spacing = new Vector2(1, 0);
Direction = FillDirection.Horizontal;
var icon = rulesets.GetRuleset(rulesetId)?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle };
var icon = rulesets.GetRuleset(rulesetId)?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle };
Add(icon.With(i =>
{
i.Size = new Vector2(14);
+26 -31
View File
@@ -38,7 +38,7 @@ namespace osu.Game.Beatmaps
CircleSize = 0,
OverallDifficulty = 0,
},
Ruleset = new DummyRulesetInfo()
Ruleset = new DummyRuleset().RulesetInfo
}, audio)
{
this.textures = textures;
@@ -54,42 +54,37 @@ namespace osu.Game.Beatmaps
public override Stream GetStream(string storagePath) => null;
private class DummyRulesetInfo : RulesetInfo
private class DummyRuleset : Ruleset
{
public override Ruleset CreateInstance() => new DummyRuleset();
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
private class DummyRuleset : Ruleset
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
{
public override IEnumerable<Mod> GetModsFor(ModType type) => Array.Empty<Mod>();
throw new NotImplementedException();
}
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new DummyBeatmapConverter { Beatmap = beatmap };
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null;
public override string Description => "dummy";
public override string ShortName => "dummy";
private class DummyBeatmapConverter : IBeatmapConverter
{
public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
public IBeatmap Beatmap { get; set; }
public bool CanConvert() => true;
public IBeatmap Convert(CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
foreach (var obj in Beatmap.HitObjects)
ObjectConverted?.Invoke(obj, obj.Yield());
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new DummyBeatmapConverter { Beatmap = beatmap };
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => null;
public override string Description => "dummy";
public override string ShortName => "dummy";
private class DummyBeatmapConverter : IBeatmapConverter
{
public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
public IBeatmap Beatmap { get; set; }
public bool CanConvert() => true;
public IBeatmap Convert(CancellationToken cancellationToken = default)
{
foreach (var obj in Beatmap.HitObjects)
ObjectConverted?.Invoke(obj, obj.Yield());
return Beatmap;
}
return Beatmap;
}
}
}
@@ -201,7 +201,11 @@ namespace osu.Game.Beatmaps.Formats
switch (pair.Key)
{
case @"Bookmarks":
beatmap.BeatmapInfo.StoredBookmarks = pair.Value;
beatmap.BeatmapInfo.Bookmarks = pair.Value.Split(',').Select(v =>
{
bool result = int.TryParse(v, out int val);
return new { result, val };
}).Where(p => p.result).Select(p => p.val).ToArray();
break;
case @"DistanceSpacing":
-20
View File
@@ -1,20 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Database;
namespace osu.Game.Beatmaps
{
public interface IBeatmapModelManager : IModelManager<BeatmapSetInfo>
{
/// <summary>
/// Provide an online lookup queue component to handle populating online beatmap metadata.
/// </summary>
BeatmapOnlineLookupQueue OnlineLookupQueue { set; }
/// <summary>
/// Provide a working beatmap cache, used to invalidate entries on changes.
/// </summary>
IWorkingBeatmapCache WorkingBeatmapCache { set; }
}
}
+2 -7
View File
@@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps
/// <summary>
/// A representation of a collection of beatmap difficulties, generally packaged as an ".osz" archive.
/// </summary>
public interface IBeatmapSetInfo : IHasOnlineID<int>, IEquatable<IBeatmapSetInfo>
public interface IBeatmapSetInfo : IHasOnlineID<int>, IEquatable<IBeatmapSetInfo>, IHasNamedFiles
{
/// <summary>
/// The date when this beatmap was imported.
@@ -22,18 +22,13 @@ namespace osu.Game.Beatmaps
/// <summary>
/// The best-effort metadata representing this set. In the case metadata differs between contained beatmaps, one is arbitrarily chosen.
/// </summary>
IBeatmapMetadataInfo? Metadata { get; }
IBeatmapMetadataInfo Metadata { get; }
/// <summary>
/// All beatmaps contained in this set.
/// </summary>
IEnumerable<IBeatmapInfo> Beatmaps { get; }
/// <summary>
/// All files used by this set.
/// </summary>
IEnumerable<INamedFileUsage> Files { get; }
/// <summary>
/// The maximum star difficulty of all beatmaps in this set.
/// </summary>
+2 -2
View File
@@ -30,7 +30,7 @@ namespace osu.Game.Beatmaps
/// <summary>
/// The status of this beatmap set.
/// </summary>
BeatmapSetOnlineStatus Status { get; }
BeatmapOnlineStatus Status { get; }
/// <summary>
/// Whether or not this beatmap set has explicit content.
@@ -105,7 +105,7 @@ namespace osu.Game.Beatmaps
/// <summary>
/// Contains the current hype status of the beatmap set.
/// Non-null only for <see cref="BeatmapSetOnlineStatus.WIP"/>, <see cref="BeatmapSetOnlineStatus.Pending"/>, and <see cref="BeatmapSetOnlineStatus.Qualified"/> sets.
/// Non-null only for <see cref="BeatmapOnlineStatus.WIP"/>, <see cref="BeatmapOnlineStatus.Pending"/>, and <see cref="BeatmapOnlineStatus.Qualified"/> sets.
/// </summary>
/// <remarks>
/// See: https://github.com/ppy/osu-web/blob/93930cd02cfbd49724929912597c727c9fbadcd1/app/Models/Beatmapset.php#L155
+2 -4
View File
@@ -55,8 +55,6 @@ namespace osu.Game.Beatmaps
public void Invalidate(BeatmapSetInfo info)
{
if (info.Beatmaps == null) return;
foreach (var b in info.Beatmaps)
Invalidate(b);
}
@@ -65,7 +63,7 @@ namespace osu.Game.Beatmaps
{
lock (workingCache)
{
var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == info.ID);
var working = workingCache.FirstOrDefault(w => info.Equals(w.BeatmapInfo));
if (working != null)
{
@@ -89,7 +87,7 @@ namespace osu.Game.Beatmaps
lock (workingCache)
{
var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
var working = workingCache.FirstOrDefault(w => beatmapInfo.Equals(w.BeatmapInfo));
if (working != null)
return working;
+1 -1
View File
@@ -26,7 +26,7 @@ namespace osu.Game.Configuration
protected override void InitialiseDefaults()
{
// UI/selection defaults
SetDefault(OsuSetting.Ruleset, 0, 0, int.MaxValue);
SetDefault(OsuSetting.Ruleset, string.Empty);
SetDefault(OsuSetting.Skin, 0, -1, int.MaxValue);
SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Database;
using Realms;
#nullable enable
@@ -10,13 +8,10 @@ using Realms;
namespace osu.Game.Configuration
{
[MapTo(@"RulesetSetting")]
public class RealmRulesetSetting : RealmObject, IHasGuidPrimaryKey
public class RealmRulesetSetting : RealmObject
{
[PrimaryKey]
public Guid ID { get; set; } = Guid.NewGuid();
[Indexed]
public int RulesetID { get; set; }
public string RulesetName { get; set; } = string.Empty;
[Indexed]
public int Variant { get; set; }
+2 -88
View File
@@ -20,7 +20,6 @@ using osu.Game.IO;
using osu.Game.IO.Archives;
using osu.Game.IPC;
using osu.Game.Overlays.Notifications;
using SharpCompress.Archives.Zip;
namespace osu.Game.Database
{
@@ -82,8 +81,6 @@ namespace osu.Game.Database
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private ArchiveImportIPCChannel ipc;
private readonly Storage exportStorage;
protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore, IIpcHost importHost = null)
{
ContextFactory = contextFactory;
@@ -92,8 +89,6 @@ namespace osu.Game.Database
ModelStore.ItemUpdated += item => handleEvent(() => ItemUpdated?.Invoke(item));
ModelStore.ItemRemoved += item => handleEvent(() => ItemRemoved?.Invoke(item));
exportStorage = storage.GetStorageForDirectory(@"exports");
Files = new FileStore(contextFactory, storage);
if (importHost != null)
@@ -392,7 +387,8 @@ namespace osu.Game.Database
{
LogForModel(item, @"Beginning import...");
item.Files = archive != null ? createFileInfos(archive, Files) : new List<TFileModel>();
if (archive != null)
item.Files.AddRange(createFileInfos(archive, Files));
item.Hash = ComputeHash(item);
await Populate(item, archive, cancellationToken).ConfigureAwait(false);
@@ -451,41 +447,6 @@ namespace osu.Game.Database
return item.ToEntityFrameworkLive();
}, cancellationToken, TaskCreationOptions.HideScheduler, lowPriority ? import_scheduler_low_priority : import_scheduler).Unwrap().ConfigureAwait(false);
/// <summary>
/// Exports an item to a legacy (.zip based) package.
/// </summary>
/// <param name="item">The item to export.</param>
public void Export(TModel item)
{
var retrievedItem = ModelStore.ConsumableItems.FirstOrDefault(s => s.ID == item.ID);
if (retrievedItem == null)
throw new ArgumentException(@"Specified model could not be found", nameof(item));
string filename = $"{GetValidFilename(item.ToString())}{HandledExtensions.First()}";
using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create))
ExportModelTo(retrievedItem, stream);
exportStorage.PresentFileExternally(filename);
}
/// <summary>
/// Exports an item to the given output stream.
/// </summary>
/// <param name="model">The item to export.</param>
/// <param name="outputStream">The output stream to export to.</param>
public virtual void ExportModelTo(TModel model, Stream outputStream)
{
using (var archive = ZipArchive.Create())
{
foreach (var file in model.Files)
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.GetStoragePath()));
archive.SaveTo(outputStream);
}
}
/// <summary>
/// Replace an existing file with a new version.
/// </summary>
@@ -727,17 +688,6 @@ namespace osu.Game.Database
#region osu-stable import
/// <summary>
/// The relative path from osu-stable's data directory to import items from.
/// </summary>
protected virtual string ImportFromStablePath => null;
/// <summary>
/// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in <see cref="ImportFromStablePath"/>.
/// </summary>
protected virtual IEnumerable<string> GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath)
.Select(path => storage.GetFullPath(path));
/// <summary>
/// Whether this specified path should be removed after successful import.
/// </summary>
@@ -745,29 +695,6 @@ namespace osu.Game.Database
/// <returns>Whether to perform deletion.</returns>
protected virtual bool ShouldDeleteArchive(string path) => false;
public Task ImportFromStableAsync(StableStorage stableStorage)
{
var storage = PrepareStableStorage(stableStorage);
// Handle situations like when the user does not have a Skins folder.
if (!storage.ExistsDirectory(ImportFromStablePath))
{
string fullPath = storage.GetFullPath(ImportFromStablePath);
Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error);
return Task.CompletedTask;
}
return Task.Run(async () => await Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false));
}
/// <summary>
/// Run any required traversal operations on the stable storage location before performing operations.
/// </summary>
/// <param name="stableStorage">The stable storage.</param>
/// <returns>The usable storage. Return the unchanged <paramref name="stableStorage"/> if no traversal is required.</returns>
protected virtual Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage;
#endregion
/// <summary>
@@ -908,18 +835,5 @@ namespace osu.Game.Database
// this doesn't follow the SHA2 hashing schema intentionally, so such entries on the data store can be identified.
return Guid.NewGuid().ToString();
}
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 invalidFilenameCharacters)
filename = filename.Replace(c, '_');
return filename;
}
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ namespace osu.Game.Database
/// <param name="obj">The object to use as a reference when negotiating a local instance.</param>
/// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param>
/// <typeparam name="T">A valid EF-stored type.</typeparam>
protected virtual void Refresh<T>(ref T obj, IQueryable<T> lookupSource = null) where T : class, IHasPrimaryKey
protected void Refresh<T>(ref T obj, IQueryable<T> lookupSource = null) where T : class, IHasPrimaryKey
{
using (var usage = ContextFactory.GetForWrite())
{

Some files were not shown because too many files have changed in this diff Show More