mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 10:07:52 +08:00
Merge branch 'master' into aim-refactor-base
This commit is contained in:
commit
c3a31a019b
@ -16,7 +16,7 @@
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Code Analysis">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.2" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.3" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -52,7 +52,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1026.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1029.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -20,6 +20,7 @@ namespace osu.Android
|
||||
[Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance, Exported = true)]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osr", DataHost = "*", DataMimeType = "*/*")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-beatmap-archive")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-skin-archive")]
|
||||
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")]
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } },
|
||||
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad!" } },
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!salad" } },
|
||||
Replay = new CatchAutoGenerator(beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } },
|
||||
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||
{
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus!" } },
|
||||
ScoreInfo = new ScoreInfo { User = new User { Username = "osu!topus" } },
|
||||
Replay = new ManiaAutoGenerator((ManiaBeatmap)beatmap).Generate(),
|
||||
};
|
||||
}
|
||||
|
34
osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs
Normal file
34
osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneNoSpinnerStacking : TestSceneOsuPlayer
|
||||
{
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
BaseDifficulty = new BeatmapDifficulty { OverallDifficulty = 10 },
|
||||
Ruleset = ruleset
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
if (i % 32 < 20)
|
||||
beatmap.HitObjects.Add(new Spinner { Position = new Vector2(256, 192), StartTime = i * 200, EndTime = (i * 200) + 100 });
|
||||
}
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
set => StackHeightBindable.Value = value;
|
||||
}
|
||||
|
||||
public Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
|
||||
public virtual Vector2 StackOffset => new Vector2(StackHeight * Scale * -6.4f);
|
||||
|
||||
public double Radius => OBJECT_RADIUS * Scale;
|
||||
|
||||
|
@ -8,6 +8,7 @@ using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
@ -31,6 +32,8 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
/// </summary>
|
||||
public int MaximumBonusSpins { get; protected set; } = 1;
|
||||
|
||||
public override Vector2 StackOffset => Vector2.Zero;
|
||||
|
||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||
{
|
||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Solo;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -88,33 +89,27 @@ namespace osu.Game.Tests.Online
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeserialiseScoreInfoWithEmptyMods()
|
||||
public void TestDeserialiseSubmittableScoreWithEmptyMods()
|
||||
{
|
||||
var score = new ScoreInfo { Ruleset = new OsuRuleset().RulesetInfo };
|
||||
var score = new SubmittableScore(new ScoreInfo { Ruleset = new OsuRuleset().RulesetInfo });
|
||||
|
||||
var deserialised = JsonConvert.DeserializeObject<ScoreInfo>(JsonConvert.SerializeObject(score));
|
||||
|
||||
if (deserialised != null)
|
||||
deserialised.Ruleset = new OsuRuleset().RulesetInfo;
|
||||
var deserialised = JsonConvert.DeserializeObject<SubmittableScore>(JsonConvert.SerializeObject(score));
|
||||
|
||||
Assert.That(deserialised?.Mods.Length, Is.Zero);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeserialiseScoreInfoWithCustomModSetting()
|
||||
public void TestDeserialiseSubmittableScoreWithCustomModSetting()
|
||||
{
|
||||
var score = new ScoreInfo
|
||||
var score = new SubmittableScore(new ScoreInfo
|
||||
{
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
Mods = new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 2 } } }
|
||||
};
|
||||
});
|
||||
|
||||
var deserialised = JsonConvert.DeserializeObject<ScoreInfo>(JsonConvert.SerializeObject(score));
|
||||
var deserialised = JsonConvert.DeserializeObject<SubmittableScore>(JsonConvert.SerializeObject(score));
|
||||
|
||||
if (deserialised != null)
|
||||
deserialised.Ruleset = new OsuRuleset().RulesetInfo;
|
||||
|
||||
Assert.That(((OsuModDoubleTime)deserialised?.Mods[0])?.SpeedChange.Value, Is.EqualTo(2));
|
||||
Assert.That((deserialised?.Mods[0])?.Settings["speed_change"], Is.EqualTo(2));
|
||||
}
|
||||
|
||||
private class TestRuleset : Ruleset
|
||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Online
|
||||
|
||||
private void addAvailabilityCheckStep(string description, Func<BeatmapAvailability> expected)
|
||||
{
|
||||
AddAssert(description, () => availabilityTracker.Availability.Value.Equals(expected.Invoke()));
|
||||
AddUntilStep(description, () => availabilityTracker.Availability.Value.Equals(expected.Invoke()));
|
||||
}
|
||||
|
||||
private static BeatmapInfo getTestBeatmapInfo(string archiveFile)
|
||||
|
@ -29,6 +29,24 @@ namespace osu.Game.Tests.Skins.IO
|
||||
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public Task TestSingleImportWeirdIniFileCase() => runSkinTest(async osu =>
|
||||
{
|
||||
var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", iniFilename: "Skin.InI"), "skin.osk"));
|
||||
|
||||
// When the import filename doesn't match, it should be appended (and update the skin.ini).
|
||||
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public Task TestSingleImportMissingSectionHeader() => runSkinTest(async osu =>
|
||||
{
|
||||
var import1 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOskWithIni("test skin", "skinner", includeSectionHeader: false), "skin.osk"));
|
||||
|
||||
// When the import filename doesn't match, it should be appended (and update the skin.ini).
|
||||
assertCorrectMetadata(import1, "test skin [skin]", "skinner", osu);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public Task TestSingleImportMatchingFilename() => runSkinTest(async osu =>
|
||||
{
|
||||
@ -190,21 +208,23 @@ namespace osu.Game.Tests.Skins.IO
|
||||
return zipStream;
|
||||
}
|
||||
|
||||
private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false)
|
||||
private MemoryStream createOskWithIni(string name, string author, bool makeUnique = false, string iniFilename = @"skin.ini", bool includeSectionHeader = true)
|
||||
{
|
||||
var zipStream = new MemoryStream();
|
||||
using var zip = ZipArchive.Create();
|
||||
zip.AddEntry("skin.ini", generateSkinIni(name, author, makeUnique));
|
||||
zip.AddEntry(iniFilename, generateSkinIni(name, author, makeUnique, includeSectionHeader));
|
||||
zip.SaveTo(zipStream);
|
||||
return zipStream;
|
||||
}
|
||||
|
||||
private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true)
|
||||
private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true, bool includeSectionHeader = true)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
|
||||
writer.WriteLine("[General]");
|
||||
if (includeSectionHeader)
|
||||
writer.WriteLine("[General]");
|
||||
|
||||
writer.WriteLine($"Name: {name}");
|
||||
writer.WriteLine($"Author: {author}");
|
||||
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osuTK.Input;
|
||||
|
||||
@ -132,11 +133,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable)
|
||||
{
|
||||
return new APILegacyScoreInfo
|
||||
return new APIScoreInfo
|
||||
{
|
||||
OnlineScoreID = 2553163309,
|
||||
OnlineRulesetID = 0,
|
||||
Replay = replayAvailable,
|
||||
OnlineID = 2553163309,
|
||||
RulesetID = 0,
|
||||
Beatmap = CreateAPIBeatmapSet(new OsuRuleset().RulesetInfo).Beatmaps.First(),
|
||||
HasReplay = replayAvailable,
|
||||
User = new User
|
||||
{
|
||||
Id = 39828,
|
||||
|
@ -38,8 +38,6 @@ 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));
|
||||
|
||||
manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -204,7 +202,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestDownloadButtonHiddenWhenBeatmapExists()
|
||||
{
|
||||
createPlaylist(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo);
|
||||
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
||||
|
||||
AddStep("import beatmap", () => manager.Import(beatmap.BeatmapSet).Wait());
|
||||
|
||||
createPlaylist(beatmap);
|
||||
|
||||
assertDownloadButtonVisible(false);
|
||||
|
||||
|
@ -231,6 +231,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
|
||||
AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -290,6 +293,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddUntilStep("wait for room open", () => this.ChildrenOfType<MultiplayerMatchSubScreen>().FirstOrDefault()?.IsLoaded == true);
|
||||
AddUntilStep("wait for join", () => client.Room != null);
|
||||
|
||||
AddAssert("Check participant count correct", () => client.APIRoom?.ParticipantCount.Value == 1);
|
||||
AddAssert("Check participant list contains user", () => client.APIRoom?.RecentParticipants.Count(u => u.Id == API.LocalUser.Value.Id) == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -45,11 +45,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddNullUser()
|
||||
public void TestAddUnresolvedUser()
|
||||
{
|
||||
AddAssert("one unique panel", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 1);
|
||||
|
||||
AddStep("add non-resolvable user", () => Client.AddNullUser());
|
||||
AddStep("add non-resolvable user", () => Client.TestAddUnresolvedUser());
|
||||
AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1);
|
||||
|
||||
AddUntilStep("two unique panels", () => this.ChildrenOfType<ParticipantPanel>().Select(p => p.User).Distinct().Count() == 2);
|
||||
|
@ -21,15 +21,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestUndownloadableWithLink()
|
||||
{
|
||||
AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
AddStep("set undownloadable beatmapset with link", () => container.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = @"https://osu.ppy.sh",
|
||||
},
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = @"https://osu.ppy.sh",
|
||||
},
|
||||
});
|
||||
|
||||
@ -39,14 +36,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestUndownloadableNoLink()
|
||||
{
|
||||
AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
AddStep("set undownloadable beatmapset without link", () => container.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
},
|
||||
DownloadDisabled = true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -56,15 +50,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestPartsRemovedWithLink()
|
||||
{
|
||||
AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
AddStep("set parts-removed beatmapset with link", () => container.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
ExternalLink = @"https://osu.ppy.sh",
|
||||
},
|
||||
DownloadDisabled = false,
|
||||
ExternalLink = @"https://osu.ppy.sh",
|
||||
},
|
||||
});
|
||||
|
||||
@ -74,14 +65,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestNormal()
|
||||
{
|
||||
AddStep("set normal beatmapset", () => container.BeatmapSet = new BeatmapSetInfo
|
||||
AddStep("set normal beatmapset", () => container.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
},
|
||||
DownloadDisabled = false,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -1,15 +1,15 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Rulesets;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -35,9 +35,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
AddStep("load multiple rulesets beatmapset", () =>
|
||||
{
|
||||
selector.BeatmapSet = new BeatmapSetInfo
|
||||
selector.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = enabledRulesets.Select(r => new BeatmapInfo { Ruleset = r }).ToList()
|
||||
Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToList()
|
||||
};
|
||||
});
|
||||
|
||||
@ -53,13 +53,13 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
AddStep("load single ruleset beatmapset", () =>
|
||||
{
|
||||
selector.BeatmapSet = new BeatmapSetInfo
|
||||
selector.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
{
|
||||
new BeatmapInfo
|
||||
new APIBeatmap
|
||||
{
|
||||
Ruleset = enabledRuleset
|
||||
RulesetID = enabledRuleset.OnlineID
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -71,9 +71,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestEmptyBeatmapSet()
|
||||
{
|
||||
AddStep("load empty beatmapset", () => selector.BeatmapSet = new BeatmapSetInfo
|
||||
AddStep("load empty beatmapset", () => selector.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = new List<BeatmapInfo>()
|
||||
Beatmaps = new List<APIBeatmap>()
|
||||
});
|
||||
|
||||
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
|
||||
|
@ -49,60 +49,48 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
AddStep(@"show first", () =>
|
||||
{
|
||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
||||
overlay.ShowBeatmapSet(new APIBeatmapSet
|
||||
{
|
||||
OnlineBeatmapSetID = 1235,
|
||||
Metadata = new BeatmapMetadata
|
||||
OnlineID = 1235,
|
||||
Title = @"an awesome beatmap",
|
||||
Artist = @"naru narusegawa",
|
||||
Source = @"hinata sou",
|
||||
Tags = @"test tag tag more tag",
|
||||
Author = new User
|
||||
{
|
||||
Title = @"an awesome beatmap",
|
||||
Artist = @"naru narusegawa",
|
||||
Source = @"hinata sou",
|
||||
Tags = @"test tag tag more tag",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
Submitted = DateTime.Now,
|
||||
Ranked = DateTime.Now,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
{
|
||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
Submitted = DateTime.Now,
|
||||
Ranked = DateTime.Now,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
new APIBeatmap
|
||||
{
|
||||
StarDifficulty = 9.99,
|
||||
Version = @"TEST",
|
||||
StarRating = 9.99,
|
||||
DifficultyName = @"TEST",
|
||||
Length = 456000,
|
||||
Ruleset = rulesets.GetRuleset(3),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
RulesetID = 3,
|
||||
CircleSize = 1,
|
||||
DrainRate = 2.3f,
|
||||
OverallDifficulty = 4.5f,
|
||||
ApproachRate = 6,
|
||||
CircleCount = 111,
|
||||
SliderCount = 12,
|
||||
PlayCount = 222,
|
||||
PassCount = 21,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
CircleSize = 1,
|
||||
DrainRate = 2.3f,
|
||||
OverallDifficulty = 4.5f,
|
||||
ApproachRate = 6,
|
||||
},
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
CircleCount = 111,
|
||||
SliderCount = 12,
|
||||
PlayCount = 222,
|
||||
PassCount = 21,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -120,71 +108,15 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
AddStep(@"show undownloadable", () =>
|
||||
{
|
||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
||||
var set = getBeatmapSet();
|
||||
|
||||
set.Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
OnlineBeatmapSetID = 1234,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"undownloadable beatmap",
|
||||
Artist = @"no one",
|
||||
Source = @"some source",
|
||||
Tags = @"another test tag tag more test tags",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = "https://osu.ppy.sh",
|
||||
},
|
||||
Preview = @"https://b.ppy.sh/preview/1234.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
Submitted = DateTime.Now,
|
||||
Ranked = DateTime.Now,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" },
|
||||
Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" },
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 5.67,
|
||||
Version = @"ANOTHER TEST",
|
||||
Length = 123000,
|
||||
Ruleset = rulesets.GetRuleset(1),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 9,
|
||||
DrainRate = 8,
|
||||
OverallDifficulty = 7,
|
||||
ApproachRate = 6,
|
||||
},
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
CircleCount = 123,
|
||||
SliderCount = 45,
|
||||
PlayCount = 567,
|
||||
PassCount = 89,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = "https://osu.ppy.sh",
|
||||
};
|
||||
|
||||
overlay.ShowBeatmapSet(set);
|
||||
});
|
||||
|
||||
downloadAssert(false);
|
||||
@ -195,48 +127,30 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
AddStep("show multiple rulesets beatmap", () =>
|
||||
{
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
var beatmaps = new List<APIBeatmap>();
|
||||
|
||||
foreach (var ruleset in rulesets.AvailableRulesets.Skip(1))
|
||||
{
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
beatmaps.Add(new APIBeatmap
|
||||
{
|
||||
Version = ruleset.Name,
|
||||
Ruleset = ruleset,
|
||||
BaseDifficulty = new BeatmapDifficulty(),
|
||||
OnlineInfo = new APIBeatmap
|
||||
DifficultyName = ruleset.Name,
|
||||
RulesetID = ruleset.OnlineID,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
overlay.ShowBeatmapSet(new BeatmapSetInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"multiple rulesets beatmap",
|
||||
Artist = @"none",
|
||||
Author = new User
|
||||
{
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
}
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
},
|
||||
Beatmaps = beatmaps
|
||||
});
|
||||
var set = getBeatmapSet();
|
||||
|
||||
set.Beatmaps = beatmaps;
|
||||
|
||||
overlay.ShowBeatmapSet(set);
|
||||
});
|
||||
|
||||
AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.BeatmapInfo.Ruleset.Equals(overlay.Header.RulesetSelector.Current.Value)));
|
||||
AddAssert("shown beatmaps of current ruleset", () => overlay.Header.HeaderContent.Picker.Difficulties.All(b => b.Beatmap.Ruleset.OnlineID == overlay.Header.RulesetSelector.Current.Value.OnlineID));
|
||||
AddAssert("left-most beatmap selected", () => overlay.Header.HeaderContent.Picker.Difficulties.First().State == BeatmapPicker.DifficultySelectorState.Selected);
|
||||
}
|
||||
|
||||
@ -246,7 +160,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep("show explicit map", () =>
|
||||
{
|
||||
var beatmapSet = getBeatmapSet();
|
||||
beatmapSet.OnlineInfo.HasExplicitContent = true;
|
||||
beatmapSet.HasExplicitContent = true;
|
||||
overlay.ShowBeatmapSet(beatmapSet);
|
||||
});
|
||||
}
|
||||
@ -257,7 +171,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep("show featured map", () =>
|
||||
{
|
||||
var beatmapSet = getBeatmapSet();
|
||||
beatmapSet.OnlineInfo.TrackId = 1;
|
||||
beatmapSet.TrackId = 1;
|
||||
overlay.ShowBeatmapSet(beatmapSet);
|
||||
});
|
||||
}
|
||||
@ -274,63 +188,41 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep(@"show without reload", overlay.Show);
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createManyDifficultiesBeatmapSet()
|
||||
private APIBeatmapSet createManyDifficultiesBeatmapSet()
|
||||
{
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
var set = getBeatmapSet();
|
||||
|
||||
var beatmaps = new List<APIBeatmap>();
|
||||
|
||||
for (int i = 1; i < 41; i++)
|
||||
{
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
beatmaps.Add(new APIBeatmap
|
||||
{
|
||||
OnlineBeatmapID = i * 10,
|
||||
Version = $"Test #{i}",
|
||||
Ruleset = Ruleset.Value,
|
||||
StarDifficulty = 2 + i * 0.1,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
OnlineID = i * 10,
|
||||
DifficultyName = $"Test #{i}",
|
||||
RulesetID = Ruleset.Value.ID ?? -1,
|
||||
StarRating = 2 + i * 0.1,
|
||||
OverallDifficulty = 3.5f,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
|
||||
},
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 123,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"many difficulties beatmap",
|
||||
Artist = @"none",
|
||||
Author = new User
|
||||
{
|
||||
Username = @"BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Preview = @"https://b.ppy.sh/preview/123.mp3",
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
},
|
||||
Beatmaps = beatmaps,
|
||||
};
|
||||
set.Beatmaps = beatmaps;
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private BeatmapSetInfo getBeatmapSet()
|
||||
private APIBeatmapSet getBeatmapSet()
|
||||
{
|
||||
var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||
var beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
|
||||
|
||||
// Make sure the overlay is reloaded (see `BeatmapSetInfo.Equals`).
|
||||
beatmapSet.OnlineBeatmapSetID = nextBeatmapSetId++;
|
||||
beatmapSet.OnlineID = nextBeatmapSetId++;
|
||||
|
||||
return beatmapSet;
|
||||
}
|
||||
|
||||
|
@ -44,27 +44,21 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddStep("set second set", () => details.BeatmapSet = secondSet);
|
||||
AddAssert("ratings set", () => details.Ratings.Ratings == secondSet.Ratings);
|
||||
|
||||
static BeatmapSetInfo createSet() => new BeatmapSetInfo
|
||||
static APIBeatmapSet createSet() => new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
{
|
||||
new BeatmapInfo
|
||||
new APIBeatmap
|
||||
{
|
||||
OnlineInfo = new APIBeatmap
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
},
|
||||
}
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
},
|
||||
}
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Status = BeatmapSetOnlineStatus.Ranked
|
||||
}
|
||||
Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Status = BeatmapSetOnlineStatus.Ranked
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -59,21 +59,18 @@ namespace osu.Game.Tests.Visual.Online
|
||||
var firstBeatmap = createBeatmap();
|
||||
var secondBeatmap = createBeatmap();
|
||||
|
||||
AddStep("set first set", () => successRate.BeatmapInfo = firstBeatmap);
|
||||
AddStep("set first set", () => successRate.Beatmap = firstBeatmap);
|
||||
AddAssert("ratings set", () => successRate.Graph.FailTimes == firstBeatmap.FailTimes);
|
||||
|
||||
AddStep("set second set", () => successRate.BeatmapInfo = secondBeatmap);
|
||||
AddStep("set second set", () => successRate.Beatmap = secondBeatmap);
|
||||
AddAssert("ratings set", () => successRate.Graph.FailTimes == secondBeatmap.FailTimes);
|
||||
|
||||
static BeatmapInfo createBeatmap() => new BeatmapInfo
|
||||
static APIBeatmap createBeatmap() => new APIBeatmap
|
||||
{
|
||||
OnlineInfo = new APIBeatmap
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
}
|
||||
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -81,14 +78,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestOnlyFailMetrics()
|
||||
{
|
||||
AddStep("set beatmap", () => successRate.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("set beatmap", () => successRate.Beatmap = new APIBeatmap
|
||||
{
|
||||
OnlineInfo = new APIBeatmap
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).ToArray(),
|
||||
}
|
||||
Fails = Enumerable.Range(1, 100).ToArray(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -98,12 +92,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestEmptyMetrics()
|
||||
{
|
||||
AddStep("set beatmap", () => successRate.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("set beatmap", () => successRate.Beatmap = new APIBeatmap
|
||||
{
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes(),
|
||||
}
|
||||
FailTimes = new APIFailTimes()
|
||||
});
|
||||
|
||||
AddAssert("graph max values correct", () => successRate.ChildrenOfType<BarGraph>().All(graph => graph.MaxValue == 0));
|
||||
|
@ -69,24 +69,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert($"button {(enabled ? "enabled" : "disabled")}", () => downloadButton.DownloadEnabled == enabled);
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createSoleily()
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
ID = 1,
|
||||
OnlineBeatmapSetID = 241526,
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
ExternalLink = string.Empty,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private void createButtonWithBeatmap(BeatmapSetInfo beatmap)
|
||||
private void createButtonWithBeatmap(IBeatmapSetInfo beatmap)
|
||||
{
|
||||
AddStep("create button", () =>
|
||||
{
|
||||
@ -112,32 +95,47 @@ namespace osu.Game.Tests.Visual.Online
|
||||
});
|
||||
}
|
||||
|
||||
private BeatmapSetInfo getDownloadableBeatmapSet()
|
||||
private IBeatmapSetInfo createSoleily()
|
||||
{
|
||||
var normal = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
|
||||
normal.OnlineInfo.HasVideo = true;
|
||||
normal.OnlineInfo.HasStoryboard = true;
|
||||
|
||||
return normal;
|
||||
return new APIBeatmapSet
|
||||
{
|
||||
OnlineID = 241526,
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = false,
|
||||
ExternalLink = string.Empty,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private BeatmapSetInfo getUndownloadableBeatmapSet()
|
||||
private IBeatmapSetInfo getDownloadableBeatmapSet()
|
||||
{
|
||||
var beatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo;
|
||||
beatmap.Metadata.Artist = "test";
|
||||
beatmap.Metadata.Title = "undownloadable";
|
||||
beatmap.Metadata.AuthorString = "test";
|
||||
var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo;
|
||||
|
||||
beatmap.OnlineInfo.HasVideo = true;
|
||||
beatmap.OnlineInfo.HasStoryboard = true;
|
||||
apiBeatmapSet.HasVideo = true;
|
||||
apiBeatmapSet.HasStoryboard = true;
|
||||
|
||||
beatmap.OnlineInfo.Availability = new BeatmapSetOnlineAvailability
|
||||
return apiBeatmapSet;
|
||||
}
|
||||
|
||||
private IBeatmapSetInfo getUndownloadableBeatmapSet()
|
||||
{
|
||||
var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo;
|
||||
|
||||
apiBeatmapSet.Artist = "test";
|
||||
apiBeatmapSet.Title = "undownloadable";
|
||||
apiBeatmapSet.AuthorString = "test";
|
||||
|
||||
apiBeatmapSet.HasVideo = true;
|
||||
apiBeatmapSet.HasStoryboard = true;
|
||||
|
||||
apiBeatmapSet.Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
ExternalLink = "http://osu.ppy.sh",
|
||||
};
|
||||
|
||||
return beatmap;
|
||||
return apiBeatmapSet;
|
||||
}
|
||||
|
||||
private class TestDownloadButton : BeatmapPanelDownloadButton
|
||||
@ -146,7 +144,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
public DownloadState DownloadState => State.Value;
|
||||
|
||||
public TestDownloadButton(BeatmapSetInfo beatmapSet)
|
||||
public TestDownloadButton(IBeatmapSetInfo beatmapSet)
|
||||
: base(beatmapSet)
|
||||
{
|
||||
}
|
||||
|
@ -18,104 +18,25 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Cached(typeof(IPreviewTrackOwner))]
|
||||
public class TestSceneDirectPanel : OsuTestScene, IPreviewTrackOwner
|
||||
{
|
||||
private BeatmapSetInfo getUndownloadableBeatmapSet() => new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 123,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "undownloadable beatmap",
|
||||
Artist = "test",
|
||||
Source = "more tests",
|
||||
Author = new User
|
||||
{
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
},
|
||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
Ruleset = Ruleset.Value,
|
||||
Version = "Test",
|
||||
StarDifficulty = 6.42,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private BeatmapSetInfo getManyDifficultiesBeatmapSet(RulesetStore rulesets)
|
||||
{
|
||||
var beatmaps = new List<BeatmapInfo>();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Ruleset = rulesets.GetRuleset(i % 4),
|
||||
StarDifficulty = 2 + i % 4 * 2,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = "many difficulties beatmap",
|
||||
Artist = "test",
|
||||
Author = new User
|
||||
{
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
}
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
},
|
||||
Beatmaps = beatmaps,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
var normal = getBeatmapSet();
|
||||
normal.OnlineInfo.HasVideo = true;
|
||||
normal.OnlineInfo.HasStoryboard = true;
|
||||
normal.HasVideo = true;
|
||||
normal.HasStoryboard = true;
|
||||
|
||||
var undownloadable = getUndownloadableBeatmapSet();
|
||||
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
|
||||
var manyDifficulties = getManyDifficultiesBeatmapSet();
|
||||
|
||||
var explicitMap = getBeatmapSet();
|
||||
explicitMap.OnlineInfo.HasExplicitContent = true;
|
||||
explicitMap.HasExplicitContent = true;
|
||||
|
||||
var featuredMap = getBeatmapSet();
|
||||
featuredMap.OnlineInfo.TrackId = 1;
|
||||
featuredMap.TrackId = 1;
|
||||
|
||||
var explicitFeaturedMap = getBeatmapSet();
|
||||
explicitFeaturedMap.OnlineInfo.HasExplicitContent = true;
|
||||
explicitFeaturedMap.OnlineInfo.TrackId = 2;
|
||||
explicitFeaturedMap.HasExplicitContent = true;
|
||||
explicitFeaturedMap.TrackId = 2;
|
||||
|
||||
Child = new BasicScrollContainer
|
||||
{
|
||||
@ -145,7 +66,72 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
};
|
||||
|
||||
BeatmapSetInfo getBeatmapSet() => CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||
APIBeatmapSet getBeatmapSet() => CreateAPIBeatmapSet(Ruleset.Value);
|
||||
|
||||
APIBeatmapSet getUndownloadableBeatmapSet() => new APIBeatmapSet
|
||||
{
|
||||
OnlineID = 123,
|
||||
Title = "undownloadable beatmap",
|
||||
Artist = "test",
|
||||
Source = "more tests",
|
||||
Author = new User
|
||||
{
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
Availability = new BeatmapSetOnlineAvailability
|
||||
{
|
||||
DownloadDisabled = true,
|
||||
},
|
||||
Preview = @"https://b.ppy.sh/preview/12345.mp3",
|
||||
PlayCount = 123,
|
||||
FavouriteCount = 456,
|
||||
BPM = 111,
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
{
|
||||
new APIBeatmap
|
||||
{
|
||||
RulesetID = Ruleset.Value.ID ?? 0,
|
||||
DifficultyName = "Test",
|
||||
StarRating = 6.42,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
APIBeatmapSet getManyDifficultiesBeatmapSet()
|
||||
{
|
||||
var beatmaps = new List<APIBeatmap>();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
beatmaps.Add(new APIBeatmap
|
||||
{
|
||||
RulesetID = i % 4,
|
||||
StarRating = 2 + i % 4 * 2,
|
||||
OverallDifficulty = 3.5f,
|
||||
});
|
||||
}
|
||||
|
||||
return new APIBeatmapSet
|
||||
{
|
||||
OnlineID = 1,
|
||||
Title = "undownloadable beatmap",
|
||||
Artist = "test",
|
||||
Source = "more tests",
|
||||
Author = new User
|
||||
{
|
||||
Username = "BanchoBot",
|
||||
Id = 3,
|
||||
},
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = beatmaps,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapSet.Buttons;
|
||||
using osuTK;
|
||||
|
||||
@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestLoggedOutIn()
|
||||
{
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet { OnlineID = 88 });
|
||||
AddStep("log out", () => API.Logout());
|
||||
checkEnabled(false);
|
||||
AddStep("log in", () => API.Login("test", "test"));
|
||||
@ -40,9 +40,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
public void TestBeatmapChange()
|
||||
{
|
||||
AddStep("log in", () => API.Login("test", "test"));
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo { OnlineBeatmapSetID = 88 });
|
||||
AddStep("set valid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet { OnlineID = 88 });
|
||||
checkEnabled(true);
|
||||
AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new BeatmapSetInfo());
|
||||
AddStep("set invalid beatmap", () => favourite.BeatmapSet.Value = new APIBeatmapSet());
|
||||
checkEnabled(false);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
LeaderboardModSelector modSelector;
|
||||
FillFlowContainer<SpriteText> selectedMods;
|
||||
var ruleset = new Bindable<RulesetInfo>();
|
||||
|
||||
var ruleset = new Bindable<IRulesetInfo>();
|
||||
|
||||
Add(selectedMods = new FillFlowContainer<SpriteText>
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
@ -43,11 +44,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
};
|
||||
|
||||
var allScores = new APILegacyScores
|
||||
var allScores = new APIScoresCollection
|
||||
{
|
||||
Scores = new List<APILegacyScoreInfo>
|
||||
Scores = new List<APIScoreInfo>
|
||||
{
|
||||
new APILegacyScoreInfo
|
||||
new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -61,10 +62,10 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new OsuModFlashlight().Acronym,
|
||||
new OsuModHardRock().Acronym,
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||
new APIMod { Acronym = new OsuModFlashlight().Acronym },
|
||||
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
@ -72,7 +73,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
},
|
||||
new APILegacyScoreInfo
|
||||
new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -86,9 +87,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new OsuModFlashlight().Acronym,
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||
new APIMod { Acronym = new OsuModFlashlight().Acronym },
|
||||
},
|
||||
Rank = ScoreRank.S,
|
||||
PP = 190,
|
||||
@ -96,7 +97,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 1234789,
|
||||
Accuracy = 0.9997,
|
||||
},
|
||||
new APILegacyScoreInfo
|
||||
new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -110,8 +111,8 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||
},
|
||||
Rank = ScoreRank.B,
|
||||
PP = 180,
|
||||
@ -119,7 +120,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 12345678,
|
||||
Accuracy = 0.9854,
|
||||
},
|
||||
new APILegacyScoreInfo
|
||||
new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -133,7 +134,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
},
|
||||
Rank = ScoreRank.C,
|
||||
PP = 170,
|
||||
@ -141,7 +142,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 1234567,
|
||||
Accuracy = 0.8765,
|
||||
},
|
||||
new APILegacyScoreInfo
|
||||
new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -162,9 +163,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
}
|
||||
};
|
||||
|
||||
var myBestScore = new APILegacyUserTopScoreInfo
|
||||
var myBestScore = new APIScoreWithPosition
|
||||
{
|
||||
Score = new APILegacyScoreInfo
|
||||
Score = new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -185,9 +186,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Position = 1337,
|
||||
};
|
||||
|
||||
var myBestScoreWithNullPosition = new APILegacyUserTopScoreInfo
|
||||
var myBestScoreWithNullPosition = new APIScoreWithPosition
|
||||
{
|
||||
Score = new APILegacyScoreInfo
|
||||
Score = new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -208,11 +209,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Position = null,
|
||||
};
|
||||
|
||||
var oneScore = new APILegacyScores
|
||||
var oneScore = new APIScoresCollection
|
||||
{
|
||||
Scores = new List<APILegacyScoreInfo>
|
||||
Scores = new List<APIScoreInfo>
|
||||
{
|
||||
new APILegacyScoreInfo
|
||||
new APIScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -226,10 +227,10 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new OsuModFlashlight().Acronym,
|
||||
new OsuModHardRock().Acronym,
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||
new APIMod { Acronym = new OsuModFlashlight().Acronym },
|
||||
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
@ -273,7 +274,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private class TestScoresContainer : ScoresContainer
|
||||
{
|
||||
public new APILegacyScores Scores
|
||||
public new APIScoresCollection Scores
|
||||
{
|
||||
set => base.Scores = value;
|
||||
}
|
||||
|
@ -2,16 +2,16 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osuTK;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -19,79 +19,79 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public TestSceneUserProfileScores()
|
||||
{
|
||||
var firstScore = new ScoreInfo
|
||||
var firstScore = new APIScoreInfo
|
||||
{
|
||||
PP = 1047.21,
|
||||
Rank = ScoreRank.SH,
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
Beatmap = new APIBeatmap
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Title = "JUSTadICE (TV Size)",
|
||||
Artist = "Oomori Seiko"
|
||||
Artist = "Oomori Seiko",
|
||||
},
|
||||
Version = "Extreme"
|
||||
DifficultyName = "Extreme"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModHidden(),
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime()
|
||||
new APIMod { Acronym = new OsuModHidden().Acronym },
|
||||
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
},
|
||||
Accuracy = 0.9813
|
||||
};
|
||||
|
||||
var secondScore = new ScoreInfo
|
||||
var secondScore = new APIScoreInfo
|
||||
{
|
||||
PP = 134.32,
|
||||
Rank = ScoreRank.A,
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
Beatmap = new APIBeatmap
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Title = "Triumph & Regret",
|
||||
Artist = "typeMARS"
|
||||
Artist = "typeMARS",
|
||||
},
|
||||
Version = "[4K] Regret"
|
||||
DifficultyName = "[4K] Regret"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime(),
|
||||
new APIMod { Acronym = new OsuModHardRock().Acronym },
|
||||
new APIMod { Acronym = new OsuModDoubleTime().Acronym },
|
||||
},
|
||||
Accuracy = 0.998546
|
||||
};
|
||||
|
||||
var thirdScore = new ScoreInfo
|
||||
var thirdScore = new APIScoreInfo
|
||||
{
|
||||
PP = 96.83,
|
||||
Rank = ScoreRank.S,
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
Beatmap = new APIBeatmap
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Title = "Idolize",
|
||||
Artist = "Creo"
|
||||
Artist = "Creo",
|
||||
},
|
||||
Version = "Insane"
|
||||
DifficultyName = "Insane"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Accuracy = 0.9726
|
||||
};
|
||||
|
||||
var noPPScore = new ScoreInfo
|
||||
var noPPScore = new APIScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
Beatmap = new APIBeatmap
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Title = "C18H27NO3(extend)",
|
||||
Artist = "Team Grimoire"
|
||||
Artist = "Team Grimoire",
|
||||
},
|
||||
Version = "[4K] Cataclysmic Hypernova"
|
||||
DifficultyName = "[4K] Cataclysmic Hypernova"
|
||||
},
|
||||
Date = DateTimeOffset.Now,
|
||||
Accuracy = 0.55879
|
||||
|
@ -15,6 +15,7 @@ using osu.Game.Database;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Playlists;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
@ -65,10 +66,32 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
});
|
||||
});
|
||||
|
||||
AddUntilStep("Progress details are hidden", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent.Alpha == 0);
|
||||
|
||||
AddStep("start match", () => match.ChildrenOfType<PlaylistsReadyButton>().First().TriggerClick());
|
||||
AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAttemptLimitedMatch()
|
||||
{
|
||||
setupAndCreateRoom(room =>
|
||||
{
|
||||
room.Name.Value = "my awesome room";
|
||||
room.MaxAttempts.Value = 5;
|
||||
room.Host.Value = API.LocalUser.Value;
|
||||
room.RecentParticipants.Add(room.Host.Value);
|
||||
room.EndDate.Value = DateTimeOffset.Now.AddMinutes(5);
|
||||
room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = importedBeatmap.Value.Beatmaps.First() },
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo }
|
||||
});
|
||||
});
|
||||
|
||||
AddUntilStep("Progress details are visible", () => match.ChildrenOfType<RoomLocalUserInfo>().FirstOrDefault()?.Parent.Alpha == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlaylistItemSelectedOnCreate()
|
||||
{
|
||||
@ -91,27 +114,16 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
BeatmapSetInfo importedSet = null;
|
||||
|
||||
// this step is required to make sure the further imports actually get online IDs.
|
||||
// all the playlist logic relies on online ID matching.
|
||||
AddStep("remove all matching online IDs", () =>
|
||||
{
|
||||
var existing = manager.QueryBeatmapSets(s => s.OnlineBeatmapSetID == importedBeatmap.Value.OnlineBeatmapSetID).ToList();
|
||||
|
||||
foreach (var s in existing)
|
||||
{
|
||||
s.OnlineBeatmapSetID = null;
|
||||
foreach (var b in s.Beatmaps)
|
||||
b.OnlineBeatmapID = null;
|
||||
manager.Update(s);
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("import altered beatmap", () =>
|
||||
{
|
||||
IBeatmap beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
|
||||
|
||||
beatmap.BeatmapInfo.BaseDifficulty.CircleSize = 1;
|
||||
|
||||
// intentionally increment online IDs to clash with import below.
|
||||
beatmap.BeatmapInfo.OnlineBeatmapID++;
|
||||
beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID++;
|
||||
|
||||
importedSet = manager.Import(beatmap.BeatmapInfo.BeatmapSet).Result.Value;
|
||||
});
|
||||
|
||||
@ -144,10 +156,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
});
|
||||
}
|
||||
|
||||
private void importBeatmap()
|
||||
{
|
||||
AddStep("import beatmap", () => importedBeatmap = manager.Import(CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Result);
|
||||
}
|
||||
private void importBeatmap() => AddStep("import beatmap", () => importedBeatmap = manager.Import(CreateBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Result);
|
||||
|
||||
private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ObjectExtensions;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -88,7 +89,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("select EZ mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||
SelectedMods.Value = new[] { ruleset.CreateMod<ModEasy>() };
|
||||
});
|
||||
|
||||
@ -105,7 +106,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("select HR mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||
SelectedMods.Value = new[] { ruleset.CreateMod<ModHardRock>() };
|
||||
});
|
||||
|
||||
@ -122,9 +123,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("select unchanged Difficulty Adjust mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||
var difficultyAdjustMod = ruleset.CreateMod<ModDifficultyAdjust>();
|
||||
difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.BaseDifficulty);
|
||||
difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.Difficulty);
|
||||
SelectedMods.Value = new[] { difficultyAdjustMod };
|
||||
});
|
||||
|
||||
@ -141,9 +142,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddStep("select changed Difficulty Adjust mod", () =>
|
||||
{
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance();
|
||||
var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull();
|
||||
var difficultyAdjustMod = ruleset.CreateMod<OsuModDifficultyAdjust>();
|
||||
var originalDifficulty = advancedStats.BeatmapInfo.BaseDifficulty;
|
||||
var originalDifficulty = advancedStats.BeatmapInfo.Difficulty;
|
||||
|
||||
difficultyAdjustMod.ReadFromDifficulty(originalDifficulty);
|
||||
difficultyAdjustMod.DrainRate.Value = originalDifficulty.DrainRate - 0.5f;
|
||||
|
@ -15,6 +15,7 @@ using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
@ -684,6 +685,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
set.Beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Version = $"Stars: {i}",
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
StarDifficulty = i,
|
||||
});
|
||||
}
|
||||
@ -868,6 +870,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
OnlineBeatmapID = id++ * 10,
|
||||
Version = version,
|
||||
StarDifficulty = diff,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = diff,
|
||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
@ -54,6 +55,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
ApproachRate = 3.5f,
|
||||
},
|
||||
StarDifficulty = 5.3f,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
@ -90,6 +92,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
ApproachRate = 3.5f,
|
||||
},
|
||||
StarDifficulty = 5.3f,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
@ -119,6 +122,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
Source = "osu!",
|
||||
Tags = "this beatmap has ratings metrics but not retries or fails",
|
||||
},
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 6,
|
||||
@ -148,6 +152,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 7,
|
||||
},
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
StarDifficulty = 2.91f,
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
@ -171,6 +176,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
Source = "osu!",
|
||||
Tags = "this beatmap has no metrics",
|
||||
},
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 5,
|
||||
@ -194,6 +200,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 162,
|
||||
Ruleset = new OsuRuleset().RulesetInfo
|
||||
});
|
||||
AddStep("set online", () => api.SetState(APIState.Online));
|
||||
AddStep("set offline", () => api.SetState(APIState.Offline));
|
||||
|
@ -140,7 +140,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<StarDifficulty> GetDifficultyAsync(BeatmapInfo beatmapInfo, RulesetInfo rulesetInfo = null, IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
||||
public override async Task<StarDifficulty> GetDifficultyAsync(IBeatmapInfo beatmapInfo, IRulesetInfo rulesetInfo = null, IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (blockCalculation)
|
||||
await calculationBlocker.Task.ConfigureAwait(false);
|
||||
|
@ -110,25 +110,19 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private static readonly BeatmapSetInfo beatmap_set = new BeatmapSetInfo
|
||||
private static readonly APIBeatmapSet beatmap_set = new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305"
|
||||
}
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1094296/covers/cover@2x.jpg?1581416305"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly BeatmapSetInfo no_cover_beatmap_set = new BeatmapSetInfo
|
||||
private static readonly APIBeatmapSet no_cover_beatmap_set = new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = string.Empty
|
||||
}
|
||||
Cover = string.Empty
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -56,95 +56,71 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddStep("Set width to 300", () => content.ResizeWidthTo(300, 500));
|
||||
}
|
||||
|
||||
private static readonly List<BeatmapSetInfo> new_beatmaps = new List<BeatmapSetInfo>
|
||||
private static readonly List<APIBeatmapSet> new_beatmaps = new List<APIBeatmapSet>
|
||||
{
|
||||
new BeatmapSetInfo
|
||||
new APIBeatmapSet
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
Title = "Very Long Title (TV size) [TATOE]",
|
||||
Artist = "This artist has a really long name how is this possible",
|
||||
Author = new User
|
||||
{
|
||||
Title = "Very Long Title (TV size) [TATOE]",
|
||||
Artist = "This artist has a really long name how is this possible",
|
||||
Author = new User
|
||||
{
|
||||
Username = "author",
|
||||
Id = 100
|
||||
}
|
||||
Username = "author",
|
||||
Id = 100
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608",
|
||||
},
|
||||
Ranked = DateTimeOffset.Now
|
||||
}
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608",
|
||||
},
|
||||
Ranked = DateTimeOffset.Now
|
||||
},
|
||||
new BeatmapSetInfo
|
||||
new APIBeatmapSet
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
Title = "Very Long Title (TV size) [TATOE]",
|
||||
Artist = "This artist has a really long name how is this possible",
|
||||
Author = new User
|
||||
{
|
||||
Title = "Very Long Title (TV size) [TATOE]",
|
||||
Artist = "This artist has a really long name how is this possible",
|
||||
Author = new User
|
||||
{
|
||||
Username = "author",
|
||||
Id = 100
|
||||
}
|
||||
Username = "author",
|
||||
Id = 100
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608",
|
||||
},
|
||||
Ranked = DateTimeOffset.MinValue
|
||||
}
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608",
|
||||
},
|
||||
Ranked = DateTimeOffset.Now
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly List<BeatmapSetInfo> popular_beatmaps = new List<BeatmapSetInfo>
|
||||
private static readonly List<APIBeatmapSet> popular_beatmaps = new List<APIBeatmapSet>
|
||||
{
|
||||
new BeatmapSetInfo
|
||||
new APIBeatmapSet
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
Title = "Very Long Title (TV size) [TATOE]",
|
||||
Artist = "This artist has a really long name how is this possible",
|
||||
Author = new User
|
||||
{
|
||||
Title = "Title",
|
||||
Artist = "Artist",
|
||||
Author = new User
|
||||
{
|
||||
Username = "author",
|
||||
Id = 100
|
||||
}
|
||||
Username = "author",
|
||||
Id = 100
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg?1595295586",
|
||||
},
|
||||
FavouriteCount = 100
|
||||
}
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608",
|
||||
},
|
||||
Ranked = DateTimeOffset.Now
|
||||
},
|
||||
new BeatmapSetInfo
|
||||
new APIBeatmapSet
|
||||
{
|
||||
Metadata = new BeatmapMetadata
|
||||
Title = "Very Long Title (TV size) [TATOE]",
|
||||
Artist = "This artist has a really long name how is this possible",
|
||||
Author = new User
|
||||
{
|
||||
Title = "Title 2",
|
||||
Artist = "Artist 2",
|
||||
Author = new User
|
||||
{
|
||||
Username = "someone",
|
||||
Id = 100
|
||||
}
|
||||
Username = "author",
|
||||
Id = 100
|
||||
},
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg?1595295586",
|
||||
},
|
||||
FavouriteCount = 10
|
||||
}
|
||||
Cover = "https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg?1595456608",
|
||||
},
|
||||
Ranked = DateTimeOffset.Now
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Tests.Beatmaps.IO;
|
||||
using osuTK;
|
||||
@ -24,7 +25,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
private BeatmapSetInfo testBeatmap;
|
||||
private IAPIProvider api;
|
||||
private RulesetStore rulesets;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
@ -33,7 +33,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
private void load(OsuGameBase osu, IAPIProvider api, RulesetStore rulesets)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
|
||||
testBeatmap = ImportBeatmapTest.LoadOszIntoOsu(osu).Result;
|
||||
}
|
||||
@ -81,7 +80,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
Child = background = new TestUpdateableBeatmapBackgroundSprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Beatmap = { Value = new BeatmapInfo { BeatmapSet = req.Response?.ToBeatmapSet(rulesets) } }
|
||||
Beatmap = { Value = new APIBeatmap { BeatmapSet = req.Response } }
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
|
@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
</ItemGroup>
|
||||
|
@ -76,7 +76,7 @@ namespace osu.Game.Tournament.Components
|
||||
{
|
||||
new TournamentSpriteText
|
||||
{
|
||||
Text = Beatmap.GetDisplayTitleRomanisable(false),
|
||||
Text = Beatmap.GetDisplayTitleRomanisable(false, false),
|
||||
Font = OsuFont.Torus.With(weight: FontWeight.Bold),
|
||||
},
|
||||
new FillFlowContainer
|
||||
|
@ -88,7 +88,7 @@ namespace osu.Game.Beatmaps
|
||||
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the difficulty of.</param>
|
||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops updating the star difficulty for the given <see cref="BeatmapInfo"/>.</param>
|
||||
/// <returns>A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state (but not during updates to ruleset and mods if a stale value is already propagated).</returns>
|
||||
public IBindable<StarDifficulty?> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
|
||||
public IBindable<StarDifficulty?> GetBindableDifficulty([NotNull] IBeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken);
|
||||
|
||||
@ -99,42 +99,45 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a bindable containing the star difficulty of a <see cref="BeatmapInfo"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
|
||||
/// Retrieves a bindable containing the star difficulty of a <see cref="IBeatmapInfo"/> with a given <see cref="RulesetInfo"/> and <see cref="Mod"/> combination.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The bindable will not update to follow the currently-selected ruleset and mods or its settings.
|
||||
/// </remarks>
|
||||
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the difficulty of.</param>
|
||||
/// <param name="rulesetInfo">The <see cref="RulesetInfo"/> to get the difficulty with. If <c>null</c>, the <paramref name="beatmapInfo"/>'s ruleset is used.</param>
|
||||
/// <param name="beatmapInfo">The <see cref="IBeatmapInfo"/> to get the difficulty of.</param>
|
||||
/// <param name="rulesetInfo">The <see cref="IRulesetInfo"/> to get the difficulty with. If <c>null</c>, the <paramref name="beatmapInfo"/>'s ruleset is used.</param>
|
||||
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with. If <c>null</c>, no mods will be assumed.</param>
|
||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops updating the star difficulty for the given <see cref="BeatmapInfo"/>.</param>
|
||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops updating the star difficulty for the given <see cref="IBeatmapInfo"/>.</param>
|
||||
/// <returns>A bindable that is updated to contain the star difficulty when it becomes available. Will be null while in an initial calculating state.</returns>
|
||||
public IBindable<StarDifficulty?> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo, [CanBeNull] IEnumerable<Mod> mods,
|
||||
public IBindable<StarDifficulty?> GetBindableDifficulty([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo rulesetInfo, [CanBeNull] IEnumerable<Mod> mods,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> createBindable(beatmapInfo, rulesetInfo, mods, cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the difficulty of a <see cref="BeatmapInfo"/>.
|
||||
/// Retrieves the difficulty of a <see cref="IBeatmapInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the difficulty of.</param>
|
||||
/// <param name="rulesetInfo">The <see cref="RulesetInfo"/> to get the difficulty with.</param>
|
||||
/// <param name="beatmapInfo">The <see cref="IBeatmapInfo"/> to get the difficulty of.</param>
|
||||
/// <param name="rulesetInfo">The <see cref="IRulesetInfo"/> to get the difficulty with.</param>
|
||||
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
|
||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
|
||||
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
||||
public virtual Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null,
|
||||
public virtual Task<StarDifficulty> GetDifficultyAsync([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo rulesetInfo = null,
|
||||
[CanBeNull] IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
||||
rulesetInfo ??= beatmapInfo.Ruleset;
|
||||
|
||||
var localBeatmapInfo = beatmapInfo as BeatmapInfo;
|
||||
var localRulesetInfo = rulesetInfo as RulesetInfo;
|
||||
|
||||
// Difficulty can only be computed if the beatmap and ruleset are locally available.
|
||||
if (beatmapInfo.ID == 0 || rulesetInfo.ID == null)
|
||||
if (localBeatmapInfo == null || localRulesetInfo == null)
|
||||
{
|
||||
// If not, fall back to the existing star difficulty (e.g. from an online source).
|
||||
return Task.FromResult(new StarDifficulty(beatmapInfo.StarDifficulty, beatmapInfo.MaxCombo ?? 0));
|
||||
return Task.FromResult(new StarDifficulty(beatmapInfo.StarRating, (beatmapInfo as IBeatmapOnlineInfo)?.MaxCombo ?? 0));
|
||||
}
|
||||
|
||||
return GetAsync(new DifficultyCacheLookup(beatmapInfo, rulesetInfo, mods), cancellationToken);
|
||||
return GetAsync(new DifficultyCacheLookup(localBeatmapInfo, localRulesetInfo, mods), cancellationToken);
|
||||
}
|
||||
|
||||
protected override Task<StarDifficulty> ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken token = default)
|
||||
@ -227,12 +230,12 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BindableStarDifficulty"/> and triggers an initial value update.
|
||||
/// </summary>
|
||||
/// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> that star difficulty should correspond to.</param>
|
||||
/// <param name="initialRulesetInfo">The initial <see cref="RulesetInfo"/> to get the difficulty with.</param>
|
||||
/// <param name="beatmapInfo">The <see cref="IBeatmapInfo"/> that star difficulty should correspond to.</param>
|
||||
/// <param name="initialRulesetInfo">The initial <see cref="IRulesetInfo"/> to get the difficulty with.</param>
|
||||
/// <param name="initialMods">The initial <see cref="Mod"/>s to get the difficulty with.</param>
|
||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops updating the star difficulty for the given <see cref="BeatmapInfo"/>.</param>
|
||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops updating the star difficulty for the given <see cref="IBeatmapInfo"/>.</param>
|
||||
/// <returns>The <see cref="BindableStarDifficulty"/>.</returns>
|
||||
private BindableStarDifficulty createBindable([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo initialRulesetInfo, [CanBeNull] IEnumerable<Mod> initialMods,
|
||||
private BindableStarDifficulty createBindable([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo initialRulesetInfo, [CanBeNull] IEnumerable<Mod> initialMods,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var bindable = new BindableStarDifficulty(beatmapInfo, cancellationToken);
|
||||
@ -244,12 +247,12 @@ namespace osu.Game.Beatmaps
|
||||
/// Updates the value of a <see cref="BindableStarDifficulty"/> with a given ruleset + mods.
|
||||
/// </summary>
|
||||
/// <param name="bindable">The <see cref="BindableStarDifficulty"/> to update.</param>
|
||||
/// <param name="rulesetInfo">The <see cref="RulesetInfo"/> to update with.</param>
|
||||
/// <param name="rulesetInfo">The <see cref="IRulesetInfo"/> to update with.</param>
|
||||
/// <param name="mods">The <see cref="Mod"/>s to update with.</param>
|
||||
/// <param name="cancellationToken">A token that may be used to cancel this update.</param>
|
||||
private void updateBindable([NotNull] BindableStarDifficulty bindable, [CanBeNull] RulesetInfo rulesetInfo, [CanBeNull] IEnumerable<Mod> mods, CancellationToken cancellationToken = default)
|
||||
private void updateBindable([NotNull] BindableStarDifficulty bindable, [CanBeNull] IRulesetInfo rulesetInfo, [CanBeNull] IEnumerable<Mod> mods, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// GetDifficultyAsync will fall back to existing data from BeatmapInfo if not locally available
|
||||
// GetDifficultyAsync will fall back to existing data from IBeatmapInfo if not locally available
|
||||
// (contrary to GetAsync)
|
||||
GetDifficultyAsync(bindable.BeatmapInfo, rulesetInfo, mods, cancellationToken)
|
||||
.ContinueWith(t =>
|
||||
@ -343,10 +346,10 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
private class BindableStarDifficulty : Bindable<StarDifficulty?>
|
||||
{
|
||||
public readonly BeatmapInfo BeatmapInfo;
|
||||
public readonly IBeatmapInfo BeatmapInfo;
|
||||
public readonly CancellationToken CancellationToken;
|
||||
|
||||
public BindableStarDifficulty(BeatmapInfo beatmapInfo, CancellationToken cancellationToken)
|
||||
public BindableStarDifficulty(IBeatmapInfo beatmapInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
BeatmapInfo = beatmapInfo;
|
||||
CancellationToken = cancellationToken;
|
||||
|
@ -16,9 +16,9 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields.
|
||||
/// </summary>
|
||||
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true)
|
||||
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true, bool includeCreator = true)
|
||||
{
|
||||
var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable();
|
||||
var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable(includeCreator);
|
||||
|
||||
if (includeDifficultyName)
|
||||
{
|
||||
|
@ -34,9 +34,9 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields.
|
||||
/// </summary>
|
||||
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapMetadataInfo metadataInfo)
|
||||
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapMetadataInfo metadataInfo, bool includeCreator = true)
|
||||
{
|
||||
string author = string.IsNullOrEmpty(metadataInfo.Author) ? string.Empty : $"({metadataInfo.Author})";
|
||||
string author = !includeCreator || string.IsNullOrEmpty(metadataInfo.Author) ? string.Empty : $"({metadataInfo.Author})";
|
||||
string artistUnicode = string.IsNullOrEmpty(metadataInfo.ArtistUnicode) ? metadataInfo.Artist : metadataInfo.ArtistUnicode;
|
||||
string titleUnicode = string.IsNullOrEmpty(metadataInfo.TitleUnicode) ? metadataInfo.Title : metadataInfo.TitleUnicode;
|
||||
|
||||
|
@ -13,6 +13,9 @@ namespace osu.Game.Beatmaps
|
||||
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
|
||||
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
|
||||
|
||||
public override ArchiveDownloadRequest<BeatmapSetInfo> GetExistingDownload(BeatmapSetInfo model)
|
||||
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
||||
|
||||
public BeatmapModelDownloader(IBeatmapModelManager beatmapModelManager, IAPIProvider api, GameHost host = null)
|
||||
: base(beatmapModelManager, api, host)
|
||||
{
|
||||
|
@ -37,10 +37,10 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private readonly BeatmapInfo beatmapInfo;
|
||||
private readonly IBeatmapInfo beatmapInfo;
|
||||
|
||||
[CanBeNull]
|
||||
private readonly RulesetInfo ruleset;
|
||||
private readonly IRulesetInfo ruleset;
|
||||
|
||||
[CanBeNull]
|
||||
private readonly IReadOnlyList<Mod> mods;
|
||||
@ -60,7 +60,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
/// <param name="ruleset">The ruleset to show the difficulty with.</param>
|
||||
/// <param name="mods">The mods to show the difficulty with.</param>
|
||||
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
|
||||
public DifficultyIcon([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true)
|
||||
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, [CanBeNull] IRulesetInfo ruleset, [CanBeNull] IReadOnlyList<Mod> mods, bool shouldShowTooltip = true)
|
||||
: this(beatmapInfo, shouldShowTooltip)
|
||||
{
|
||||
this.ruleset = ruleset ?? beatmapInfo.Ruleset;
|
||||
@ -73,7 +73,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
/// <param name="beatmapInfo">The beatmap to show the difficulty of.</param>
|
||||
/// <param name="shouldShowTooltip">Whether to display a tooltip when hovered.</param>
|
||||
/// <param name="performBackgroundDifficultyLookup">Whether to perform difficulty lookup (including calculation if necessary).</param>
|
||||
public DifficultyIcon([NotNull] BeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
|
||||
public DifficultyIcon([NotNull] IBeatmapInfo beatmapInfo, bool shouldShowTooltip = true, bool performBackgroundDifficultyLookup = true)
|
||||
{
|
||||
this.beatmapInfo = beatmapInfo ?? throw new ArgumentNullException(nameof(beatmapInfo));
|
||||
this.shouldShowTooltip = shouldShowTooltip;
|
||||
@ -84,6 +84,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
@ -105,7 +108,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Child = background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colours.ForStarDifficulty(beatmapInfo.StarDifficulty) // Default value that will be re-populated once difficulty calculation completes
|
||||
Colour = colours.ForStarDifficulty(beatmapInfo.StarRating) // Default value that will be re-populated once difficulty calculation completes
|
||||
},
|
||||
},
|
||||
new ConstrainedIconContainer
|
||||
@ -114,18 +117,28 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
// the null coalesce here is only present to make unit tests work (ruleset dlls aren't copied correctly for testing at the moment)
|
||||
Icon = (ruleset ?? beatmapInfo.Ruleset)?.CreateInstance()?.CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle }
|
||||
Icon = getRulesetIcon()
|
||||
},
|
||||
};
|
||||
|
||||
if (performBackgroundDifficultyLookup)
|
||||
iconContainer.Add(new DelayedLoadUnloadWrapper(() => new DifficultyRetriever(beatmapInfo, ruleset, mods) { StarDifficulty = { BindTarget = difficultyBindable } }, 0));
|
||||
else
|
||||
difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarDifficulty, 0);
|
||||
difficultyBindable.Value = new StarDifficulty(beatmapInfo.StarRating, 0);
|
||||
|
||||
difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars));
|
||||
}
|
||||
|
||||
private Drawable getRulesetIcon()
|
||||
{
|
||||
int? onlineID = (ruleset ?? beatmapInfo.Ruleset).OnlineID;
|
||||
|
||||
if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance)
|
||||
return rulesetInstance.CreateIcon();
|
||||
|
||||
return new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle };
|
||||
}
|
||||
|
||||
ITooltip<DifficultyIconTooltipContent> IHasCustomTooltip<DifficultyIconTooltipContent>.GetCustomTooltip() => new DifficultyIconTooltip();
|
||||
|
||||
DifficultyIconTooltipContent IHasCustomTooltip<DifficultyIconTooltipContent>.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmapInfo, difficultyBindable) : null;
|
||||
@ -134,8 +147,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public readonly Bindable<StarDifficulty> StarDifficulty = new Bindable<StarDifficulty>();
|
||||
|
||||
private readonly BeatmapInfo beatmapInfo;
|
||||
private readonly RulesetInfo ruleset;
|
||||
private readonly IBeatmapInfo beatmapInfo;
|
||||
private readonly IRulesetInfo ruleset;
|
||||
private readonly IReadOnlyList<Mod> mods;
|
||||
|
||||
private CancellationTokenSource difficultyCancellation;
|
||||
@ -143,7 +156,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
[Resolved]
|
||||
private BeatmapDifficultyCache difficultyCache { get; set; }
|
||||
|
||||
public DifficultyRetriever(BeatmapInfo beatmapInfo, RulesetInfo ruleset, IReadOnlyList<Mod> mods)
|
||||
public DifficultyRetriever(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, IReadOnlyList<Mod> mods)
|
||||
{
|
||||
this.beatmapInfo = beatmapInfo;
|
||||
this.ruleset = ruleset;
|
||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public void SetContent(DifficultyIconTooltipContent content)
|
||||
{
|
||||
difficultyName.Text = content.BeatmapInfo.Version;
|
||||
difficultyName.Text = content.BeatmapInfo.DifficultyName;
|
||||
|
||||
starDifficulty.UnbindAll();
|
||||
starDifficulty.BindTo(content.Difficulty);
|
||||
@ -109,10 +109,10 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
internal class DifficultyIconTooltipContent
|
||||
{
|
||||
public readonly BeatmapInfo BeatmapInfo;
|
||||
public readonly IBeatmapInfo BeatmapInfo;
|
||||
public readonly IBindable<StarDifficulty> Difficulty;
|
||||
|
||||
public DifficultyIconTooltipContent(BeatmapInfo beatmapInfo, IBindable<StarDifficulty> difficulty)
|
||||
public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable<StarDifficulty> difficulty)
|
||||
{
|
||||
BeatmapInfo = beatmapInfo;
|
||||
Difficulty = difficulty;
|
||||
|
@ -19,8 +19,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
/// </remarks>
|
||||
public class GroupedDifficultyIcon : DifficultyIcon
|
||||
{
|
||||
public GroupedDifficultyIcon(List<BeatmapInfo> beatmaps, RulesetInfo ruleset, Color4 counterColour)
|
||||
: base(beatmaps.OrderBy(b => b.StarDifficulty).Last(), ruleset, null, false)
|
||||
public GroupedDifficultyIcon(IEnumerable<IBeatmapInfo> beatmaps, IRulesetInfo ruleset, Color4 counterColour)
|
||||
: base(beatmaps.OrderBy(b => b.StarRating).Last(), ruleset, null, false)
|
||||
{
|
||||
AddInternal(new OsuSpriteText
|
||||
{
|
||||
@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Padding = new MarginPadding { Left = Size.X },
|
||||
Margin = new MarginPadding { Left = 2, Right = 5 },
|
||||
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold),
|
||||
Text = beatmaps.Count.ToString(),
|
||||
Text = beatmaps.Count().ToString(),
|
||||
Colour = counterColour,
|
||||
});
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected override void ParseStreamInto(LineBufferedReader stream, T output)
|
||||
{
|
||||
Section section = Section.None;
|
||||
Section section = Section.General;
|
||||
|
||||
string line;
|
||||
|
||||
@ -47,10 +47,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
if (line.StartsWith('[') && line.EndsWith(']'))
|
||||
{
|
||||
if (!Enum.TryParse(line[1..^1], out section))
|
||||
{
|
||||
Logger.Log($"Unknown section \"{line}\" in \"{output}\"");
|
||||
section = Section.None;
|
||||
}
|
||||
|
||||
OnBeginNewSection(section);
|
||||
continue;
|
||||
@ -148,7 +145,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected enum Section
|
||||
{
|
||||
None,
|
||||
General,
|
||||
Editor,
|
||||
Metadata,
|
||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// A single beatmap difficulty.
|
||||
/// </summary>
|
||||
public interface IBeatmapInfo : IHasOnlineID
|
||||
public interface IBeatmapInfo : IHasOnlineID<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// The user-specified name given to this beatmap.
|
||||
|
@ -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
|
||||
public interface IBeatmapSetInfo : IHasOnlineID<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// The date when this beatmap was imported.
|
||||
|
@ -5,15 +5,15 @@
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public interface IHasOnlineID
|
||||
public interface IHasOnlineID<out T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The server-side ID representing this instance, if one exists. Any value 0 or less denotes a missing ID.
|
||||
/// The server-side ID representing this instance, if one exists. Any value 0 or less denotes a missing ID (except in special cases where autoincrement is not used, like rulesets).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Generally we use -1 when specifying "missing" in code, but values of 0 are also considered missing as the online source
|
||||
/// is generally a MySQL autoincrement value, which can never be 0.
|
||||
/// </remarks>
|
||||
int OnlineID { get; }
|
||||
T OnlineID { get; }
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Database
|
||||
private readonly IModelManager<TModel> modelManager;
|
||||
private readonly IAPIProvider api;
|
||||
|
||||
private readonly List<ArchiveDownloadRequest<TModel>> currentDownloads = new List<ArchiveDownloadRequest<TModel>>();
|
||||
protected readonly List<ArchiveDownloadRequest<TModel>> CurrentDownloads = new List<ArchiveDownloadRequest<TModel>>();
|
||||
|
||||
protected ModelDownloader(IModelManager<TModel> modelManager, IAPIProvider api, IIpcHost importHost = null)
|
||||
{
|
||||
@ -74,7 +74,7 @@ namespace osu.Game.Database
|
||||
if (!imported.Any())
|
||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||
|
||||
currentDownloads.Remove(request);
|
||||
CurrentDownloads.Remove(request);
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
};
|
||||
|
||||
@ -86,7 +86,7 @@ namespace osu.Game.Database
|
||||
return true;
|
||||
};
|
||||
|
||||
currentDownloads.Add(request);
|
||||
CurrentDownloads.Add(request);
|
||||
PostNotification?.Invoke(notification);
|
||||
|
||||
api.PerformAsync(request);
|
||||
@ -96,7 +96,7 @@ namespace osu.Game.Database
|
||||
|
||||
void triggerFailure(Exception error)
|
||||
{
|
||||
currentDownloads.Remove(request);
|
||||
CurrentDownloads.Remove(request);
|
||||
|
||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||
|
||||
@ -107,7 +107,7 @@ namespace osu.Game.Database
|
||||
}
|
||||
}
|
||||
|
||||
public ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model) => currentDownloads.Find(r => r.Model.Equals(model));
|
||||
public abstract ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model);
|
||||
|
||||
private bool canDownload(TModel model) => GetExistingDownload(model) == null && api != null;
|
||||
|
||||
|
@ -6,9 +6,11 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Development;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Statistics;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Models;
|
||||
using Realms;
|
||||
|
||||
@ -32,8 +34,9 @@ namespace osu.Game.Database
|
||||
/// Version history:
|
||||
/// 6 First tracked version (~20211018)
|
||||
/// 7 Changed OnlineID fields to non-nullable to add indexing support (20211018)
|
||||
/// 8 Rebind scroll adjust keys to not have control modifier (20211029)
|
||||
/// </summary>
|
||||
private const int schema_version = 7;
|
||||
private const int schema_version = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking context creation during blocking periods.
|
||||
@ -148,6 +151,21 @@ namespace osu.Game.Database
|
||||
|
||||
private void onMigration(Migration migration, ulong lastSchemaVersion)
|
||||
{
|
||||
if (lastSchemaVersion < 8)
|
||||
{
|
||||
// Ctrl -/+ now adjusts UI scale so let's clear any bindings which overlap these combinations.
|
||||
// New defaults will be populated by the key store afterwards.
|
||||
var keyBindings = migration.NewRealm.All<RealmKeyBinding>();
|
||||
|
||||
var increaseSpeedBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.IncreaseScrollSpeed);
|
||||
if (increaseSpeedBinding != null && increaseSpeedBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Control, InputKey.Plus }))
|
||||
migration.NewRealm.Remove(increaseSpeedBinding);
|
||||
|
||||
var decreaseSpeedBinding = keyBindings.FirstOrDefault(k => k.ActionInt == (int)GlobalAction.DecreaseScrollSpeed);
|
||||
if (decreaseSpeedBinding != null && decreaseSpeedBinding.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Control, InputKey.Minus }))
|
||||
migration.NewRealm.Remove(decreaseSpeedBinding);
|
||||
}
|
||||
|
||||
if (lastSchemaVersion < 7)
|
||||
{
|
||||
convertOnlineIDs<RealmBeatmap>();
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -58,39 +59,34 @@ namespace osu.Game.Graphics.Containers
|
||||
}
|
||||
|
||||
public void AddLink(string text, string url, Action<SpriteText> creationParameters = null) =>
|
||||
createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.External, url), url);
|
||||
createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.External, url), url);
|
||||
|
||||
public void AddLink(string text, Action action, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||
=> createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action);
|
||||
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.Custom, string.Empty), tooltipText, action);
|
||||
|
||||
public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||
=> createLink(AddText(text, creationParameters), new LinkDetails(action, argument), tooltipText);
|
||||
=> createLink(CreateChunkFor(text, true, CreateSpriteText, creationParameters), new LinkDetails(action, argument), tooltipText);
|
||||
|
||||
public void AddLink(LocalisableString text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
|
||||
{
|
||||
var spriteText = new OsuSpriteText { Text = text };
|
||||
|
||||
AddText(spriteText, creationParameters);
|
||||
createLink(spriteText.Yield(), new LinkDetails(action, argument), tooltipText);
|
||||
RemoveInternal(spriteText); // TODO: temporary, will go away when TextParts support localisation properly.
|
||||
createLink(new TextPartManual(spriteText.Yield()), new LinkDetails(action, argument), tooltipText);
|
||||
}
|
||||
|
||||
public void AddLink(IEnumerable<SpriteText> text, LinkAction action, string linkArgument, string tooltipText = null)
|
||||
{
|
||||
foreach (var t in text)
|
||||
AddArbitraryDrawable(t);
|
||||
|
||||
createLink(text, new LinkDetails(action, linkArgument), tooltipText);
|
||||
createLink(new TextPartManual(text), new LinkDetails(action, linkArgument), tooltipText);
|
||||
}
|
||||
|
||||
public void AddUserLink(User user, Action<SpriteText> creationParameters = null)
|
||||
=> createLink(AddText(user.Username, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user.Id.ToString()), "view profile");
|
||||
=> createLink(CreateChunkFor(user.Username, true, CreateSpriteText, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user.Id.ToString()), "view profile");
|
||||
|
||||
private void createLink(IEnumerable<Drawable> drawables, LinkDetails link, string tooltipText, Action action = null)
|
||||
private void createLink(ITextPart textPart, LinkDetails link, LocalisableString tooltipText, Action action = null)
|
||||
{
|
||||
var linkCompiler = CreateLinkCompiler(drawables.OfType<SpriteText>());
|
||||
linkCompiler.RelativeSizeAxes = Axes.Both;
|
||||
linkCompiler.TooltipText = tooltipText;
|
||||
linkCompiler.Action = () =>
|
||||
Action onClickAction = () =>
|
||||
{
|
||||
if (action != null)
|
||||
action();
|
||||
@ -101,10 +97,41 @@ namespace osu.Game.Graphics.Containers
|
||||
host.OpenUrlExternally(link.Argument);
|
||||
};
|
||||
|
||||
AddInternal(linkCompiler);
|
||||
AddPart(new TextLink(textPart, tooltipText, onClickAction));
|
||||
}
|
||||
|
||||
protected virtual DrawableLinkCompiler CreateLinkCompiler(IEnumerable<SpriteText> parts) => new DrawableLinkCompiler(parts);
|
||||
private class TextLink : TextPart
|
||||
{
|
||||
private readonly ITextPart innerPart;
|
||||
private readonly LocalisableString tooltipText;
|
||||
private readonly Action action;
|
||||
|
||||
public TextLink(ITextPart innerPart, LocalisableString tooltipText, Action action)
|
||||
{
|
||||
this.innerPart = innerPart;
|
||||
this.tooltipText = tooltipText;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Drawable> CreateDrawablesFor(TextFlowContainer textFlowContainer)
|
||||
{
|
||||
var linkFlowContainer = (LinkFlowContainer)textFlowContainer;
|
||||
|
||||
innerPart.RecreateDrawablesFor(linkFlowContainer);
|
||||
var drawables = innerPart.Drawables.ToList();
|
||||
|
||||
drawables.Add(linkFlowContainer.CreateLinkCompiler(innerPart).With(c =>
|
||||
{
|
||||
c.RelativeSizeAxes = Axes.Both;
|
||||
c.TooltipText = tooltipText;
|
||||
c.Action = action;
|
||||
}));
|
||||
|
||||
return drawables;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual DrawableLinkCompiler CreateLinkCompiler(ITextPart textPart) => new DrawableLinkCompiler(textPart);
|
||||
|
||||
// We want the compilers to always be visible no matter where they are, so RelativeSizeAxes is used.
|
||||
// However due to https://github.com/ppy/osu-framework/issues/2073, it's possible for the compilers to be relative size in the flow's auto-size axes - an unsupported operation.
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
@ -19,8 +19,8 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
|
||||
|
||||
public void AddArbitraryDrawable(Drawable drawable) => AddInternal(drawable);
|
||||
public ITextPart AddArbitraryDrawable(Drawable drawable) => AddPart(new TextPartManual(drawable.Yield()));
|
||||
|
||||
public IEnumerable<Drawable> AddIcon(IconUsage icon, Action<SpriteText> creationParameters = null) => AddText(icon.Icon.ToString(), creationParameters);
|
||||
public ITextPart AddIcon(IconUsage icon, Action<SpriteText> creationParameters = null) => AddText(icon.Icon.ToString(), creationParameters);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -10,7 +10,7 @@ namespace osu.Game.Graphics
|
||||
{
|
||||
public class ErrorTextFlowContainer : OsuTextFlowContainer
|
||||
{
|
||||
private readonly List<Drawable> errorDrawables = new List<Drawable>();
|
||||
private readonly List<ITextPart> errorTextParts = new List<ITextPart>();
|
||||
|
||||
public ErrorTextFlowContainer()
|
||||
: base(cp => cp.Font = cp.Font.With(size: 12))
|
||||
@ -19,7 +19,8 @@ namespace osu.Game.Graphics
|
||||
|
||||
public void ClearErrors()
|
||||
{
|
||||
errorDrawables.ForEach(d => d.Expire());
|
||||
foreach (var textPart in errorTextParts)
|
||||
RemovePart(textPart);
|
||||
}
|
||||
|
||||
public void AddErrors(string[] errors)
|
||||
@ -29,7 +30,7 @@ namespace osu.Game.Graphics
|
||||
if (errors == null) return;
|
||||
|
||||
foreach (string error in errors)
|
||||
errorDrawables.AddRange(AddParagraph(error, cp => cp.Colour = Color4.Red));
|
||||
errorTextParts.Add(AddParagraph(error, cp => cp.Colour = Color4.Red));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(InputKey.ExtraMouseButton2, GlobalAction.SkipCutscene),
|
||||
new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Tilde }, GlobalAction.QuickExit),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed),
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
|
||||
new KeyBinding(new[] { InputKey.F3 }, GlobalAction.DecreaseScrollSpeed),
|
||||
new KeyBinding(new[] { InputKey.F4 }, GlobalAction.IncreaseScrollSpeed),
|
||||
new KeyBinding(new[] { InputKey.Shift, InputKey.Tab }, GlobalAction.ToggleInGameInterface),
|
||||
new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay),
|
||||
new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay),
|
||||
|
@ -119,6 +119,16 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@"show_cursor_in_screenshots"), @"Show menu cursor in screenshots");
|
||||
|
||||
/// <summary>
|
||||
/// "Video"
|
||||
/// </summary>
|
||||
public static LocalisableString VideoHeader => new TranslatableString(getKey(@"video_header"), @"Video");
|
||||
|
||||
/// <summary>
|
||||
/// "Use hardware acceleration"
|
||||
/// </summary>
|
||||
public static LocalisableString UseHardwareAcceleration => new TranslatableString(getKey(@"use_hardware_acceleration"), @"Use hardware acceleration");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
@ -9,21 +9,20 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetScoresRequest : APIRequest<APILegacyScores>
|
||||
public class GetScoresRequest : APIRequest<APIScoresCollection>
|
||||
{
|
||||
private readonly BeatmapInfo beatmapInfo;
|
||||
private readonly IBeatmapInfo beatmapInfo;
|
||||
private readonly BeatmapLeaderboardScope scope;
|
||||
private readonly RulesetInfo ruleset;
|
||||
private readonly IRulesetInfo ruleset;
|
||||
private readonly IEnumerable<IMod> mods;
|
||||
|
||||
public GetScoresRequest(BeatmapInfo beatmapInfo, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod> mods = null)
|
||||
public GetScoresRequest(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<IMod> mods = null)
|
||||
{
|
||||
if (!beatmapInfo.OnlineBeatmapID.HasValue)
|
||||
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
|
||||
if (beatmapInfo.OnlineID <= 0)
|
||||
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(IBeatmapInfo.OnlineID)}.");
|
||||
|
||||
if (scope == BeatmapLeaderboardScope.Local)
|
||||
throw new InvalidOperationException("Should not attempt to request online scores for a local scoped leaderboard");
|
||||
@ -32,30 +31,9 @@ namespace osu.Game.Online.API.Requests
|
||||
this.scope = scope;
|
||||
this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset));
|
||||
this.mods = mods ?? Array.Empty<IMod>();
|
||||
|
||||
Success += onSuccess;
|
||||
}
|
||||
|
||||
private void onSuccess(APILegacyScores r)
|
||||
{
|
||||
Debug.Assert(ruleset.ID != null, "ruleset.ID != null");
|
||||
|
||||
foreach (APILegacyScoreInfo score in r.Scores)
|
||||
{
|
||||
score.BeatmapInfo = beatmapInfo;
|
||||
score.OnlineRulesetID = ruleset.ID.Value;
|
||||
}
|
||||
|
||||
var userScore = r.UserScore;
|
||||
|
||||
if (userScore != null)
|
||||
{
|
||||
userScore.Score.BeatmapInfo = beatmapInfo;
|
||||
userScore.Score.OnlineRulesetID = ruleset.ID.Value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmaps/{beatmapInfo.OnlineBeatmapID}/scores{createQueryParameters()}";
|
||||
protected override string Target => $@"beatmaps/{beatmapInfo.OnlineID}/scores{createQueryParameters()}";
|
||||
|
||||
private string createQueryParameters()
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserScoresRequest : PaginatedAPIRequest<List<APILegacyScoreInfo>>
|
||||
public class GetUserScoresRequest : PaginatedAPIRequest<List<APIScoreInfo>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly ScoreType type;
|
||||
|
@ -43,16 +43,16 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
public double StarRating { get; set; }
|
||||
|
||||
[JsonProperty(@"drain")]
|
||||
private float drainRate { get; set; }
|
||||
public float DrainRate { get; set; }
|
||||
|
||||
[JsonProperty(@"cs")]
|
||||
private float circleSize { get; set; }
|
||||
public float CircleSize { get; set; }
|
||||
|
||||
[JsonProperty(@"ar")]
|
||||
private float approachRate { get; set; }
|
||||
public float ApproachRate { get; set; }
|
||||
|
||||
[JsonProperty(@"accuracy")]
|
||||
private float overallDifficulty { get; set; }
|
||||
public float OverallDifficulty { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public double Length { get; set; }
|
||||
@ -100,10 +100,10 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
MaxCombo = MaxCombo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
DrainRate = drainRate,
|
||||
CircleSize = circleSize,
|
||||
ApproachRate = approachRate,
|
||||
OverallDifficulty = overallDifficulty,
|
||||
DrainRate = DrainRate,
|
||||
CircleSize = CircleSize,
|
||||
ApproachRate = ApproachRate,
|
||||
OverallDifficulty = OverallDifficulty,
|
||||
},
|
||||
OnlineInfo = this,
|
||||
};
|
||||
@ -115,10 +115,10 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
|
||||
public IBeatmapDifficultyInfo Difficulty => new BeatmapDifficulty
|
||||
{
|
||||
DrainRate = drainRate,
|
||||
CircleSize = circleSize,
|
||||
ApproachRate = approachRate,
|
||||
OverallDifficulty = overallDifficulty,
|
||||
DrainRate = DrainRate,
|
||||
CircleSize = CircleSize,
|
||||
ApproachRate = ApproachRate,
|
||||
OverallDifficulty = OverallDifficulty,
|
||||
};
|
||||
|
||||
IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet;
|
||||
|
@ -1,35 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APILegacyScores
|
||||
{
|
||||
[JsonProperty(@"scores")]
|
||||
public List<APILegacyScoreInfo> Scores;
|
||||
|
||||
[JsonProperty(@"userScore")]
|
||||
public APILegacyUserTopScoreInfo UserScore;
|
||||
}
|
||||
|
||||
public class APILegacyUserTopScoreInfo
|
||||
{
|
||||
[JsonProperty(@"position")]
|
||||
public int? Position;
|
||||
|
||||
[JsonProperty(@"score")]
|
||||
public APILegacyScoreInfo Score;
|
||||
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
|
||||
{
|
||||
var score = Score.CreateScoreInfo(rulesets);
|
||||
score.Position = Position;
|
||||
return score;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -15,36 +16,102 @@ using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APILegacyScoreInfo
|
||||
public class APIScoreInfo : IScoreInfo
|
||||
{
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
|
||||
[JsonProperty(@"score")]
|
||||
public long TotalScore { get; set; }
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
public long OnlineID { get; set; }
|
||||
|
||||
[JsonProperty(@"replay")]
|
||||
public bool HasReplay { get; set; }
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
public DateTimeOffset Date { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmap")]
|
||||
public APIBeatmap Beatmap { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty(@"pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmapset")]
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
var ruleset = rulesets.GetRuleset(OnlineRulesetID);
|
||||
set
|
||||
{
|
||||
// in the deserialisation case we need to ferry this data across.
|
||||
// the order of properties returned by the API guarantees that the beatmap is populated by this point.
|
||||
if (!(Beatmap is APIBeatmap apiBeatmap))
|
||||
throw new InvalidOperationException("Beatmap set metadata arrived before beatmap metadata in response");
|
||||
|
||||
apiBeatmap.BeatmapSet = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("statistics")]
|
||||
public Dictionary<string, int> Statistics { get; set; }
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
private string[] mods { set => Mods = value.Select(acronym => new APIMod { Acronym = acronym }); }
|
||||
|
||||
[NotNull]
|
||||
public IEnumerable<APIMod> Mods { get; set; } = Array.Empty<APIMod>();
|
||||
|
||||
[JsonProperty("rank")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ScoreRank Rank { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ScoreInfo"/> from an API score instance.
|
||||
/// </summary>
|
||||
/// <param name="rulesets">A ruleset store, used to populate a ruleset instance in the returned score.</param>
|
||||
/// <param name="beatmap">An optional beatmap, copied into the returned score (for cases where the API does not populate the beatmap).</param>
|
||||
/// <returns></returns>
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
|
||||
{
|
||||
var ruleset = rulesets.GetRuleset(RulesetID);
|
||||
|
||||
var rulesetInstance = ruleset.CreateInstance();
|
||||
|
||||
var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.CreateModFromAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty<Mod>();
|
||||
var modInstances = Mods.Select(apiMod => rulesetInstance.CreateModFromAcronym(apiMod.Acronym)).Where(m => m != null).ToArray();
|
||||
|
||||
// all API scores provided by this class are considered to be legacy.
|
||||
mods = mods.Append(rulesetInstance.CreateMod<ModClassic>()).ToArray();
|
||||
modInstances = modInstances.Append(rulesetInstance.CreateMod<ModClassic>()).ToArray();
|
||||
|
||||
var scoreInfo = new ScoreInfo
|
||||
{
|
||||
TotalScore = TotalScore,
|
||||
MaxCombo = MaxCombo,
|
||||
BeatmapInfo = Beatmap.ToBeatmapInfo(rulesets),
|
||||
User = User,
|
||||
Accuracy = Accuracy,
|
||||
OnlineScoreID = OnlineScoreID,
|
||||
OnlineScoreID = OnlineID,
|
||||
Date = Date,
|
||||
PP = PP,
|
||||
BeatmapInfo = BeatmapInfo,
|
||||
RulesetID = OnlineRulesetID,
|
||||
Hash = Replay ? "online" : string.Empty, // todo: temporary?
|
||||
RulesetID = RulesetID,
|
||||
Hash = HasReplay ? "online" : string.Empty, // todo: temporary?
|
||||
Rank = Rank,
|
||||
Ruleset = ruleset,
|
||||
Mods = mods,
|
||||
Mods = modInstances,
|
||||
};
|
||||
|
||||
if (beatmap != null)
|
||||
scoreInfo.BeatmapInfo = beatmap;
|
||||
|
||||
if (Statistics != null)
|
||||
{
|
||||
foreach (var kvp in Statistics)
|
||||
@ -81,57 +148,8 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
return scoreInfo;
|
||||
}
|
||||
|
||||
[JsonProperty(@"score")]
|
||||
public int TotalScore { get; set; }
|
||||
public IRulesetInfo Ruleset => new RulesetInfo { ID = RulesetID };
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
public long OnlineScoreID { get; set; }
|
||||
|
||||
[JsonProperty(@"replay")]
|
||||
public bool Replay { get; set; }
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
public DateTimeOffset Date { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmap")]
|
||||
public BeatmapInfo BeatmapInfo { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty(@"pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmapset")]
|
||||
public BeatmapMetadata Metadata
|
||||
{
|
||||
set
|
||||
{
|
||||
// extract the set ID to its correct place.
|
||||
BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = value.ID };
|
||||
value.ID = 0;
|
||||
|
||||
BeatmapInfo.Metadata = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty(@"statistics")]
|
||||
public Dictionary<string, int> Statistics { get; set; }
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
public int OnlineRulesetID { get; set; }
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
public string[] Mods { get; set; }
|
||||
|
||||
[JsonProperty("rank")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ScoreRank Rank { get; set; }
|
||||
IBeatmapInfo IScoreInfo.Beatmap => Beatmap;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIScoreWithPosition
|
||||
{
|
||||
[JsonProperty(@"position")]
|
||||
public int? Position;
|
||||
|
||||
[JsonProperty(@"score")]
|
||||
public APIScoreInfo Score;
|
||||
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
|
||||
{
|
||||
var score = Score.CreateScoreInfo(rulesets, beatmap);
|
||||
score.Position = Position;
|
||||
return score;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIScoresCollection
|
||||
{
|
||||
[JsonProperty(@"scores")]
|
||||
public List<APIScoreInfo> Scores;
|
||||
|
||||
[JsonProperty(@"userScore")]
|
||||
public APIScoreWithPosition UserScore;
|
||||
}
|
||||
}
|
155
osu.Game/Online/BeatmapDownloadTracker.cs
Normal file
155
osu.Game/Online/BeatmapDownloadTracker.cs
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Online
|
||||
{
|
||||
public class BeatmapDownloadTracker : DownloadTracker<IBeatmapSetInfo>
|
||||
{
|
||||
[Resolved(CanBeNull = true)]
|
||||
protected BeatmapManager? Manager { get; private set; }
|
||||
|
||||
private ArchiveDownloadRequest<BeatmapSetInfo>? attachedRequest;
|
||||
|
||||
public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem)
|
||||
: base(trackedItem)
|
||||
{
|
||||
}
|
||||
|
||||
private IBindable<WeakReference<BeatmapSetInfo>>? managerUpdated;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>>? managerRemoved;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadFailed;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load()
|
||||
{
|
||||
if (Manager == null)
|
||||
return;
|
||||
|
||||
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
||||
var beatmapSetInfo = new BeatmapSetInfo { OnlineBeatmapSetID = TrackedItem.OnlineID };
|
||||
|
||||
if (Manager.IsAvailableLocally(beatmapSetInfo))
|
||||
UpdateState(DownloadState.LocallyAvailable);
|
||||
else
|
||||
attachDownload(Manager.GetExistingDownload(beatmapSetInfo));
|
||||
|
||||
managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy();
|
||||
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||
managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy();
|
||||
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||
managerUpdated = Manager.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(itemUpdated);
|
||||
managerRemoved = Manager.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
}
|
||||
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(request.Model, TrackedItem))
|
||||
attachDownload(request);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(request.Model, TrackedItem))
|
||||
attachDownload(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void attachDownload(ArchiveDownloadRequest<BeatmapSetInfo>? request)
|
||||
{
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
attachedRequest.Failure -= onRequestFailure;
|
||||
attachedRequest.DownloadProgressed -= onRequestProgress;
|
||||
attachedRequest.Success -= onRequestSuccess;
|
||||
}
|
||||
|
||||
attachedRequest = request;
|
||||
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
if (attachedRequest.Progress == 1)
|
||||
{
|
||||
UpdateProgress(1);
|
||||
UpdateState(DownloadState.Importing);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateProgress(attachedRequest.Progress);
|
||||
UpdateState(DownloadState.Downloading);
|
||||
|
||||
attachedRequest.Failure += onRequestFailure;
|
||||
attachedRequest.DownloadProgressed += onRequestProgress;
|
||||
attachedRequest.Success += onRequestSuccess;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateState(DownloadState.NotDownloaded);
|
||||
}
|
||||
}
|
||||
|
||||
private void onRequestSuccess(string _) => Schedule(() => UpdateState(DownloadState.Importing));
|
||||
|
||||
private void onRequestProgress(float progress) => Schedule(() => UpdateProgress(progress));
|
||||
|
||||
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||
|
||||
private void itemUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(item, TrackedItem))
|
||||
UpdateState(DownloadState.LocallyAvailable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void itemRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(item, TrackedItem))
|
||||
UpdateState(DownloadState.NotDownloaded);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private bool checkEquality(IBeatmapSetInfo x, IBeatmapSetInfo y) => x.OnlineID == y.OnlineID;
|
||||
|
||||
#region Disposal
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
attachDownload(null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -30,6 +32,11 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts);
|
||||
|
||||
public DrawableLinkCompiler(ITextPart part)
|
||||
: this(part.Drawables.OfType<SpriteText>())
|
||||
{
|
||||
}
|
||||
|
||||
public DrawableLinkCompiler(IEnumerable<Drawable> parts)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
|
39
osu.Game/Online/DownloadTracker.cs
Normal file
39
osu.Game/Online/DownloadTracker.cs
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Online
|
||||
{
|
||||
public abstract class DownloadTracker<T> : Component
|
||||
where T : class
|
||||
{
|
||||
public readonly T TrackedItem;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current download state of the download - whether is has already been downloaded, is in progress, or is not downloaded.
|
||||
/// </summary>
|
||||
public IBindable<DownloadState> State => state;
|
||||
|
||||
private readonly Bindable<DownloadState> state = new Bindable<DownloadState>();
|
||||
|
||||
/// <summary>
|
||||
/// The progress of an active download.
|
||||
/// </summary>
|
||||
public IBindableNumber<double> Progress => progress;
|
||||
|
||||
private readonly BindableNumber<double> progress = new BindableNumber<double> { MinValue = 0, MaxValue = 1 };
|
||||
|
||||
protected DownloadTracker(T trackedItem)
|
||||
{
|
||||
TrackedItem = trackedItem;
|
||||
}
|
||||
|
||||
protected void UpdateState(DownloadState newState) => state.Value = newState;
|
||||
|
||||
protected void UpdateProgress(double newProgress) => progress.Value = newProgress;
|
||||
}
|
||||
}
|
@ -1,196 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.API;
|
||||
|
||||
namespace osu.Game.Online
|
||||
{
|
||||
/// <summary>
|
||||
/// A component which tracks a <typeparamref name="TModel"/> through potential download/import/deletion.
|
||||
/// </summary>
|
||||
public abstract class DownloadTrackingComposite<TModel, TModelManager> : CompositeDrawable
|
||||
where TModel : class, IEquatable<TModel>
|
||||
where TModelManager : class, IModelDownloader<TModel>, IModelManager<TModel>
|
||||
{
|
||||
protected readonly Bindable<TModel> Model = new Bindable<TModel>();
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
protected TModelManager Manager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Holds the current download state of the <typeparamref name="TModel"/>, whether is has already been downloaded, is in progress, or is not downloaded.
|
||||
/// </summary>
|
||||
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||
|
||||
protected readonly BindableNumber<double> Progress = new BindableNumber<double> { MinValue = 0, MaxValue = 1 };
|
||||
|
||||
protected DownloadTrackingComposite(TModel model = null)
|
||||
{
|
||||
Model.Value = model;
|
||||
}
|
||||
|
||||
private IBindable<WeakReference<TModel>> managerUpdated;
|
||||
private IBindable<WeakReference<TModel>> managerRemoved;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadFailed;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load()
|
||||
{
|
||||
Model.BindValueChanged(modelInfo =>
|
||||
{
|
||||
if (modelInfo.NewValue == null)
|
||||
attachDownload(null);
|
||||
else if (IsModelAvailableLocally())
|
||||
State.Value = DownloadState.LocallyAvailable;
|
||||
else
|
||||
attachDownload(Manager?.GetExistingDownload(modelInfo.NewValue));
|
||||
}, true);
|
||||
|
||||
if (Manager == null)
|
||||
return;
|
||||
|
||||
managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy();
|
||||
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||
managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy();
|
||||
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||
managerUpdated = Manager.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(itemUpdated);
|
||||
managerRemoved = Manager.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that a database model matches the one expected to be downloaded.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// For online play, this could be used to check that the databased model matches the online beatmap.
|
||||
/// </example>
|
||||
/// <param name="databasedModel">The model in database.</param>
|
||||
protected virtual bool VerifyDatabasedModel([NotNull] TModel databasedModel) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given model is available in the database.
|
||||
/// By default, this calls <see cref="IModelManager{TModel}.IsAvailableLocally"/>,
|
||||
/// but can be overriden to add additional checks for verifying the model in database.
|
||||
/// </summary>
|
||||
protected virtual bool IsModelAvailableLocally() => Manager?.IsAvailableLocally(Model.Value) == true;
|
||||
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<TModel>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (request.Model.Equals(Model.Value))
|
||||
attachDownload(request);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<TModel>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (request.Model.Equals(Model.Value))
|
||||
attachDownload(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private ArchiveDownloadRequest<TModel> attachedRequest;
|
||||
|
||||
private void attachDownload(ArchiveDownloadRequest<TModel> request)
|
||||
{
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
attachedRequest.Failure -= onRequestFailure;
|
||||
attachedRequest.DownloadProgressed -= onRequestProgress;
|
||||
attachedRequest.Success -= onRequestSuccess;
|
||||
}
|
||||
|
||||
attachedRequest = request;
|
||||
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
if (attachedRequest.Progress == 1)
|
||||
{
|
||||
Progress.Value = 1;
|
||||
State.Value = DownloadState.Importing;
|
||||
}
|
||||
else
|
||||
{
|
||||
Progress.Value = attachedRequest.Progress;
|
||||
State.Value = DownloadState.Downloading;
|
||||
|
||||
attachedRequest.Failure += onRequestFailure;
|
||||
attachedRequest.DownloadProgressed += onRequestProgress;
|
||||
attachedRequest.Success += onRequestSuccess;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
State.Value = DownloadState.NotDownloaded;
|
||||
}
|
||||
}
|
||||
|
||||
private void onRequestSuccess(string _) => Schedule(() => State.Value = DownloadState.Importing);
|
||||
|
||||
private void onRequestProgress(float progress) => Schedule(() => Progress.Value = progress);
|
||||
|
||||
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||
|
||||
private void itemUpdated(ValueChangedEvent<WeakReference<TModel>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (!item.Equals(Model.Value))
|
||||
return;
|
||||
|
||||
if (!VerifyDatabasedModel(item))
|
||||
{
|
||||
State.Value = DownloadState.NotDownloaded;
|
||||
return;
|
||||
}
|
||||
|
||||
State.Value = DownloadState.LocallyAvailable;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void itemRemoved(ValueChangedEvent<WeakReference<TModel>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (item.Equals(Model.Value))
|
||||
State.Value = DownloadState.NotDownloaded;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#region Disposal
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
State.UnbindAll();
|
||||
|
||||
attachDownload(null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -148,6 +148,10 @@ namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
Room = joinedRoom;
|
||||
APIRoom = room;
|
||||
|
||||
Debug.Assert(LocalUser != null);
|
||||
addUserToAPIRoom(LocalUser);
|
||||
|
||||
foreach (var user in joinedRoom.Users)
|
||||
updateUserPlayingState(user.UserID, user.State);
|
||||
|
||||
@ -372,6 +376,8 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
Room.Users.Add(user);
|
||||
|
||||
addUserToAPIRoom(user);
|
||||
|
||||
UserJoined?.Invoke(user);
|
||||
RoomUpdated?.Invoke();
|
||||
});
|
||||
@ -391,6 +397,18 @@ namespace osu.Game.Online.Multiplayer
|
||||
return handleUserLeft(user, UserKicked);
|
||||
}
|
||||
|
||||
private void addUserToAPIRoom(MultiplayerRoomUser user)
|
||||
{
|
||||
Debug.Assert(APIRoom != null);
|
||||
|
||||
APIRoom.RecentParticipants.Add(user.User ?? new User
|
||||
{
|
||||
Id = user.UserID,
|
||||
Username = "[Unresolved]"
|
||||
});
|
||||
APIRoom.ParticipantCount.Value++;
|
||||
}
|
||||
|
||||
private Task handleUserLeft(MultiplayerRoomUser user, Action<MultiplayerRoomUser>? callback)
|
||||
{
|
||||
if (Room == null)
|
||||
@ -404,6 +422,10 @@ namespace osu.Game.Online.Multiplayer
|
||||
Room.Users.Remove(user);
|
||||
PlayingUserIds.Remove(user.UserID);
|
||||
|
||||
Debug.Assert(APIRoom != null);
|
||||
APIRoom.RecentParticipants.RemoveAll(u => u.Id == user.UserID);
|
||||
APIRoom.ParticipantCount.Value--;
|
||||
|
||||
callback?.Invoke(user);
|
||||
RoomUpdated?.Invoke();
|
||||
}, false);
|
||||
|
@ -2,8 +2,10 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -16,19 +18,27 @@ namespace osu.Game.Online.Rooms
|
||||
/// This differs from a regular download tracking composite as this accounts for the
|
||||
/// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap.
|
||||
/// </summary>
|
||||
public class OnlinePlayBeatmapAvailabilityTracker : DownloadTrackingComposite<BeatmapSetInfo, BeatmapManager>
|
||||
public sealed class OnlinePlayBeatmapAvailabilityTracker : CompositeDrawable
|
||||
{
|
||||
public readonly IBindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
|
||||
|
||||
// Required to allow child components to update. Can potentially be replaced with a `CompositeComponent` class if or when we make one.
|
||||
protected override bool RequiresChildrenUpdate => true;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The availability state of the currently selected playlist item.
|
||||
/// </summary>
|
||||
public IBindable<BeatmapAvailability> Availability => availability;
|
||||
|
||||
private readonly Bindable<BeatmapAvailability> availability = new Bindable<BeatmapAvailability>(BeatmapAvailability.LocallyAvailable());
|
||||
private readonly Bindable<BeatmapAvailability> availability = new Bindable<BeatmapAvailability>(BeatmapAvailability.NotDownloaded());
|
||||
|
||||
private ScheduledDelegate progressUpdate;
|
||||
|
||||
private BeatmapDownloadTracker downloadTracker;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -40,58 +50,38 @@ namespace osu.Game.Online.Rooms
|
||||
if (item.NewValue == null)
|
||||
return;
|
||||
|
||||
Model.Value = item.NewValue.Beatmap.Value.BeatmapSet;
|
||||
downloadTracker?.RemoveAndDisposeImmediately();
|
||||
|
||||
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
|
||||
downloadTracker.State.BindValueChanged(_ => updateAvailability());
|
||||
downloadTracker.Progress.BindValueChanged(_ =>
|
||||
{
|
||||
if (downloadTracker.State.Value != DownloadState.Downloading)
|
||||
return;
|
||||
|
||||
// incoming progress changes are going to be at a very high rate.
|
||||
// we don't want to flood the network with this, so rate limit how often we send progress updates.
|
||||
if (progressUpdate?.Completed != false)
|
||||
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
||||
});
|
||||
|
||||
AddInternal(downloadTracker);
|
||||
}, true);
|
||||
|
||||
Progress.BindValueChanged(_ =>
|
||||
{
|
||||
if (State.Value != DownloadState.Downloading)
|
||||
return;
|
||||
|
||||
// incoming progress changes are going to be at a very high rate.
|
||||
// we don't want to flood the network with this, so rate limit how often we send progress updates.
|
||||
if (progressUpdate?.Completed != false)
|
||||
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
||||
});
|
||||
|
||||
State.BindValueChanged(_ => updateAvailability(), true);
|
||||
}
|
||||
|
||||
protected override bool VerifyDatabasedModel(BeatmapSetInfo databasedSet)
|
||||
{
|
||||
int beatmapId = SelectedItem.Value?.Beatmap.Value.OnlineID ?? -1;
|
||||
string checksum = SelectedItem.Value?.Beatmap.Value.MD5Hash;
|
||||
|
||||
var matchingBeatmap = databasedSet.Beatmaps.FirstOrDefault(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum);
|
||||
|
||||
if (matchingBeatmap == null)
|
||||
{
|
||||
Logger.Log("The imported beatmap set does not match the online version.", LoggingTarget.Runtime, LogLevel.Important);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool IsModelAvailableLocally()
|
||||
{
|
||||
int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID;
|
||||
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
|
||||
|
||||
var beatmap = Manager.QueryBeatmap(b => b.OnlineBeatmapID == onlineId && b.MD5Hash == checksum);
|
||||
return beatmap?.BeatmapSet.DeletePending == false;
|
||||
}
|
||||
|
||||
private void updateAvailability()
|
||||
{
|
||||
switch (State.Value)
|
||||
if (downloadTracker == null)
|
||||
return;
|
||||
|
||||
switch (downloadTracker.State.Value)
|
||||
{
|
||||
case DownloadState.NotDownloaded:
|
||||
availability.Value = BeatmapAvailability.NotDownloaded();
|
||||
break;
|
||||
|
||||
case DownloadState.Downloading:
|
||||
availability.Value = BeatmapAvailability.Downloading((float)Progress.Value);
|
||||
availability.Value = BeatmapAvailability.Downloading((float)downloadTracker.Progress.Value);
|
||||
break;
|
||||
|
||||
case DownloadState.Importing:
|
||||
@ -99,12 +89,27 @@ namespace osu.Game.Online.Rooms
|
||||
break;
|
||||
|
||||
case DownloadState.LocallyAvailable:
|
||||
availability.Value = BeatmapAvailability.LocallyAvailable();
|
||||
bool hashMatches = checkHashValidity();
|
||||
|
||||
availability.Value = hashMatches ? BeatmapAvailability.LocallyAvailable() : BeatmapAvailability.NotDownloaded();
|
||||
|
||||
// only display a message to the user if a download seems to have just completed.
|
||||
if (!hashMatches && downloadTracker.Progress.Value == 1)
|
||||
Logger.Log("The imported beatmap set does not match the online version.", LoggingTarget.Runtime, LogLevel.Important);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(State));
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private bool checkHashValidity()
|
||||
{
|
||||
int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID;
|
||||
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
|
||||
|
||||
return beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
155
osu.Game/Online/ScoreDownloadTracker.cs
Normal file
155
osu.Game/Online/ScoreDownloadTracker.cs
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Online
|
||||
{
|
||||
public class ScoreDownloadTracker : DownloadTracker<ScoreInfo>
|
||||
{
|
||||
[Resolved(CanBeNull = true)]
|
||||
protected ScoreManager? Manager { get; private set; }
|
||||
|
||||
private ArchiveDownloadRequest<ScoreInfo>? attachedRequest;
|
||||
|
||||
public ScoreDownloadTracker(ScoreInfo trackedItem)
|
||||
: base(trackedItem)
|
||||
{
|
||||
}
|
||||
|
||||
private IBindable<WeakReference<ScoreInfo>>? managerUpdated;
|
||||
private IBindable<WeakReference<ScoreInfo>>? managerRemoved;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadFailed;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load()
|
||||
{
|
||||
if (Manager == null)
|
||||
return;
|
||||
|
||||
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
||||
var scoreInfo = new ScoreInfo { OnlineScoreID = TrackedItem.OnlineScoreID };
|
||||
|
||||
if (Manager.IsAvailableLocally(scoreInfo))
|
||||
UpdateState(DownloadState.LocallyAvailable);
|
||||
else
|
||||
attachDownload(Manager.GetExistingDownload(scoreInfo));
|
||||
|
||||
managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy();
|
||||
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||
managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy();
|
||||
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||
managerUpdated = Manager.ItemUpdated.GetBoundCopy();
|
||||
managerUpdated.BindValueChanged(itemUpdated);
|
||||
managerRemoved = Manager.ItemRemoved.GetBoundCopy();
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
}
|
||||
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(request.Model, TrackedItem))
|
||||
attachDownload(request);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(request.Model, TrackedItem))
|
||||
attachDownload(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void attachDownload(ArchiveDownloadRequest<ScoreInfo>? request)
|
||||
{
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
attachedRequest.Failure -= onRequestFailure;
|
||||
attachedRequest.DownloadProgressed -= onRequestProgress;
|
||||
attachedRequest.Success -= onRequestSuccess;
|
||||
}
|
||||
|
||||
attachedRequest = request;
|
||||
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
if (attachedRequest.Progress == 1)
|
||||
{
|
||||
UpdateProgress(1);
|
||||
UpdateState(DownloadState.Importing);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateProgress(attachedRequest.Progress);
|
||||
UpdateState(DownloadState.Downloading);
|
||||
|
||||
attachedRequest.Failure += onRequestFailure;
|
||||
attachedRequest.DownloadProgressed += onRequestProgress;
|
||||
attachedRequest.Success += onRequestSuccess;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateState(DownloadState.NotDownloaded);
|
||||
}
|
||||
}
|
||||
|
||||
private void onRequestSuccess(string _) => Schedule(() => UpdateState(DownloadState.Importing));
|
||||
|
||||
private void onRequestProgress(float progress) => Schedule(() => UpdateProgress(progress));
|
||||
|
||||
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||
|
||||
private void itemUpdated(ValueChangedEvent<WeakReference<ScoreInfo>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(item, TrackedItem))
|
||||
UpdateState(DownloadState.LocallyAvailable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void itemRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> weakItem)
|
||||
{
|
||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (checkEquality(item, TrackedItem))
|
||||
UpdateState(DownloadState.NotDownloaded);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private bool checkEquality(ScoreInfo x, ScoreInfo y) => x.OnlineScoreID == y.OnlineScoreID;
|
||||
|
||||
#region Disposal
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
attachDownload(null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -16,13 +16,13 @@ namespace osu.Game.Online.Solo
|
||||
|
||||
private readonly int beatmapId;
|
||||
|
||||
private readonly ScoreInfo scoreInfo;
|
||||
private readonly SubmittableScore score;
|
||||
|
||||
public SubmitSoloScoreRequest(int beatmapId, long scoreId, ScoreInfo scoreInfo)
|
||||
{
|
||||
this.beatmapId = beatmapId;
|
||||
this.scoreId = scoreId;
|
||||
this.scoreInfo = scoreInfo;
|
||||
score = new SubmittableScore(scoreInfo);
|
||||
}
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
@ -32,7 +32,7 @@ namespace osu.Game.Online.Solo
|
||||
req.ContentType = "application/json";
|
||||
req.Method = HttpMethod.Put;
|
||||
|
||||
req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings
|
||||
req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||
}));
|
||||
|
75
osu.Game/Online/Solo/SubmittableScore.cs
Normal file
75
osu.Game/Online/Solo/SubmittableScore.cs
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.Solo
|
||||
{
|
||||
/// <summary>
|
||||
/// A class specifically for sending scores to the API during score submission.
|
||||
/// This is used instead of <see cref="APIScoreInfo"/> due to marginally different serialisation naming requirements.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SubmittableScore
|
||||
{
|
||||
[JsonProperty("rank")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ScoreRank Rank { get; set; }
|
||||
|
||||
[JsonProperty("total_score")]
|
||||
public long TotalScore { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty(@"pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
[JsonProperty("max_combo")]
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
[JsonProperty("ruleset_id")]
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[JsonProperty("passed")]
|
||||
public bool Passed { get; set; }
|
||||
|
||||
// Used for API serialisation/deserialisation.
|
||||
[JsonProperty("mods")]
|
||||
public APIMod[] Mods { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty("statistics")]
|
||||
public Dictionary<HitResult, int> Statistics { get; set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
public SubmittableScore()
|
||||
{
|
||||
}
|
||||
|
||||
public SubmittableScore(ScoreInfo score)
|
||||
{
|
||||
Rank = score.Rank;
|
||||
TotalScore = score.TotalScore;
|
||||
Accuracy = score.Accuracy;
|
||||
PP = score.PP;
|
||||
MaxCombo = score.MaxCombo;
|
||||
RulesetID = score.RulesetID;
|
||||
Passed = score.Passed;
|
||||
Mods = score.APIMods;
|
||||
User = score.User;
|
||||
Statistics = score.Statistics;
|
||||
}
|
||||
}
|
||||
}
|
@ -158,6 +158,8 @@ namespace osu.Game
|
||||
|
||||
private Bindable<int> configRuleset;
|
||||
|
||||
private Bindable<float> uiScale;
|
||||
|
||||
private Bindable<int> configSkin;
|
||||
|
||||
private readonly string[] args;
|
||||
@ -219,6 +221,7 @@ namespace osu.Game
|
||||
|
||||
// bind config int to database RulesetInfo
|
||||
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
||||
uiScale = LocalConfig.GetBindable<float>(OsuSetting.UIScale);
|
||||
|
||||
var preferredRuleset = RulesetStore.GetRuleset(configRuleset.Value);
|
||||
|
||||
@ -433,11 +436,15 @@ namespace osu.Game
|
||||
/// <item>first beatmap from any ruleset.</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public void PresentBeatmap(BeatmapSetInfo beatmap, Predicate<BeatmapInfo> difficultyCriteria = null)
|
||||
public void PresentBeatmap(IBeatmapSetInfo beatmap, Predicate<BeatmapInfo> difficultyCriteria = null)
|
||||
{
|
||||
var databasedSet = beatmap.OnlineBeatmapSetID != null
|
||||
? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID)
|
||||
: BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash);
|
||||
BeatmapSetInfo databasedSet = null;
|
||||
|
||||
if (beatmap.OnlineID > 0)
|
||||
databasedSet = BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineID);
|
||||
|
||||
if (beatmap is BeatmapSetInfo localBeatmap)
|
||||
databasedSet ??= BeatmapManager.QueryBeatmapSet(s => s.Hash == localBeatmap.Hash);
|
||||
|
||||
if (databasedSet == null)
|
||||
{
|
||||
@ -1020,6 +1027,28 @@ namespace osu.Game
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
||||
{
|
||||
const float adjustment_increment = 0.05f;
|
||||
|
||||
switch (e.Action)
|
||||
{
|
||||
case PlatformAction.ZoomIn:
|
||||
uiScale.Value += adjustment_increment;
|
||||
return true;
|
||||
|
||||
case PlatformAction.ZoomOut:
|
||||
uiScale.Value -= adjustment_increment;
|
||||
return true;
|
||||
|
||||
case PlatformAction.ZoomDefault:
|
||||
uiScale.SetDefault();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnPressed(e);
|
||||
}
|
||||
|
||||
#region Inactive audio dimming
|
||||
|
||||
private readonly BindableDouble inactiveVolumeFade = new BindableDouble();
|
||||
|
@ -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 System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
@ -37,7 +36,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private ShakeContainer registerShake;
|
||||
private IEnumerable<Drawable> characterCheckText;
|
||||
private ITextPart characterCheckText;
|
||||
|
||||
private OsuTextBox[] textboxes;
|
||||
private LoadingLayer loadingLayer;
|
||||
@ -136,7 +135,7 @@ namespace osu.Game.Overlays.AccountCreation
|
||||
characterCheckText = passwordDescription.AddText("8 characters long");
|
||||
passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song.");
|
||||
|
||||
passwordTextBox.Current.ValueChanged += password => { characterCheckText.ForEach(s => s.Colour = password.NewValue.Length == 0 ? Color4.White : Interpolation.ValueAt(password.NewValue.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); };
|
||||
passwordTextBox.Current.ValueChanged += password => { characterCheckText.Drawables.ForEach(s => s.Colour = password.NewValue.Length == 0 ? Color4.White : Interpolation.ValueAt(password.NewValue.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); };
|
||||
}
|
||||
|
||||
public override void OnEntering(IScreen last)
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public abstract class BeatmapDownloadTrackingComposite : DownloadTrackingComposite<BeatmapSetInfo, BeatmapManager>
|
||||
{
|
||||
public Bindable<BeatmapSetInfo> BeatmapSet => Model;
|
||||
|
||||
protected BeatmapDownloadTrackingComposite(BeatmapSetInfo set = null)
|
||||
: base(set)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -12,9 +12,9 @@ using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osuTK;
|
||||
@ -206,7 +206,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
|
||||
getSetsRequest.Success += response =>
|
||||
{
|
||||
var sets = response.BeatmapSets.Select(responseJson => responseJson.ToBeatmapSet(rulesets)).ToList();
|
||||
var sets = response.BeatmapSets.ToList();
|
||||
|
||||
// If the previous request returned a null cursor, the API is indicating we can't paginate further (maybe there are no more beatmaps left).
|
||||
if (sets.Count == 0 || response.Cursor == null)
|
||||
@ -289,7 +289,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
/// Contains the beatmap sets returned from API.
|
||||
/// Valid for read if and only if <see cref="Type"/> is <see cref="SearchResultType.ResultsReturned"/>.
|
||||
/// </summary>
|
||||
public List<BeatmapSetInfo> Results { get; private set; }
|
||||
public List<APIBeatmapSet> Results { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the names of supporter-only filters requested by the user.
|
||||
@ -297,7 +297,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
/// </summary>
|
||||
public List<LocalisableString> SupporterOnlyFiltersUsed { get; private set; }
|
||||
|
||||
public static SearchResult ResultsReturned(List<BeatmapSetInfo> results) => new SearchResult
|
||||
public static SearchResult ResultsReturned(List<APIBeatmapSet> results) => new SearchResult
|
||||
{
|
||||
Type = SearchResultType.ResultsReturned,
|
||||
Results = results
|
||||
|
@ -8,12 +8,12 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
@ -49,17 +49,17 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
|
||||
public Bindable<SearchExplicit> ExplicitContent => explicitContentFilter.Current;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == null || string.IsNullOrEmpty(value.OnlineInfo.Covers.Cover))
|
||||
if (value == null || string.IsNullOrEmpty(value.Covers.Cover))
|
||||
{
|
||||
beatmapCover.FadeOut(600, Easing.OutQuint);
|
||||
return;
|
||||
}
|
||||
|
||||
beatmapCover.OnlineInfo = value.OnlineInfo;
|
||||
beatmapCover.OnlineInfo = value;
|
||||
beatmapCover.FadeTo(0.1f, 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -30,7 +31,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
public abstract class BeatmapPanel : OsuClickableContainer, IHasContextMenu
|
||||
{
|
||||
public readonly BeatmapSetInfo SetInfo;
|
||||
public readonly APIBeatmapSet SetInfo;
|
||||
|
||||
private const double hover_transition_time = 400;
|
||||
private const int maximum_difficulty_icons = 10;
|
||||
@ -49,10 +50,10 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
|
||||
protected Action ViewBeatmap;
|
||||
|
||||
protected BeatmapPanel(BeatmapSetInfo setInfo)
|
||||
protected BeatmapPanel(APIBeatmapSet setInfo)
|
||||
: base(HoverSampleSet.Submit)
|
||||
{
|
||||
Debug.Assert(setInfo.OnlineBeatmapSetID != null);
|
||||
Debug.Assert(setInfo.OnlineID > 0);
|
||||
|
||||
SetInfo = setInfo;
|
||||
}
|
||||
@ -95,8 +96,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
|
||||
Action = ViewBeatmap = () =>
|
||||
{
|
||||
Debug.Assert(SetInfo.OnlineBeatmapSetID != null);
|
||||
beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineBeatmapSetID.Value);
|
||||
Debug.Assert(SetInfo.OnlineID > 0);
|
||||
beatmapSetOverlay?.FetchAndShowBeatmapSet(SetInfo.OnlineID);
|
||||
};
|
||||
}
|
||||
|
||||
@ -146,14 +147,14 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
var icons = new List<DifficultyIcon>();
|
||||
|
||||
if (SetInfo.Beatmaps.Count > maximum_difficulty_icons)
|
||||
if (SetInfo.Beatmaps.Count() > maximum_difficulty_icons)
|
||||
{
|
||||
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
|
||||
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
|
||||
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.Where(b => b.RulesetID == ruleset.OnlineID).ToList(), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.Ruleset.ID).ThenBy(beatmap => beatmap.StarDifficulty))
|
||||
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.RulesetID).ThenBy(beatmap => beatmap.StarRating))
|
||||
icons.Add(new DifficultyIcon(b));
|
||||
}
|
||||
|
||||
@ -163,7 +164,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
protected Drawable CreateBackground() => new UpdateableOnlineBeatmapSetCover
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
OnlineInfo = SetInfo.OnlineInfo,
|
||||
OnlineInfo = SetInfo,
|
||||
};
|
||||
|
||||
public class Statistic : FillFlowContainer
|
||||
|
@ -5,37 +5,54 @@ using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
public class BeatmapPanelDownloadButton : BeatmapDownloadTrackingComposite
|
||||
public class BeatmapPanelDownloadButton : CompositeDrawable
|
||||
{
|
||||
protected bool DownloadEnabled => button.Enabled.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Currently selected beatmap. Used to present the correct difficulty after completing a download.
|
||||
/// </summary>
|
||||
public readonly IBindable<BeatmapInfo> SelectedBeatmap = new Bindable<BeatmapInfo>();
|
||||
public readonly IBindable<APIBeatmap> SelectedBeatmap = new Bindable<APIBeatmap>();
|
||||
|
||||
private readonly ShakeContainer shakeContainer;
|
||||
private readonly DownloadButton button;
|
||||
private Bindable<bool> noVideoSetting;
|
||||
|
||||
public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet)
|
||||
: base(beatmapSet)
|
||||
protected readonly BeatmapDownloadTracker DownloadTracker;
|
||||
|
||||
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||
|
||||
private readonly IBeatmapSetInfo beatmapSet;
|
||||
|
||||
public BeatmapPanelDownloadButton(IBeatmapSetInfo beatmapSet)
|
||||
{
|
||||
InternalChild = shakeContainer = new ShakeContainer
|
||||
this.beatmapSet = beatmapSet;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = button = new DownloadButton
|
||||
shakeContainer = new ShakeContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = button = new DownloadButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
State = { BindTarget = State }
|
||||
},
|
||||
},
|
||||
DownloadTracker = new BeatmapDownloadTracker(beatmapSet)
|
||||
{
|
||||
State = { BindTarget = State }
|
||||
}
|
||||
};
|
||||
|
||||
button.Add(new DownloadProgressBar(beatmapSet)
|
||||
@ -46,14 +63,6 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
button.State.BindTo(State);
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuGame game, BeatmapManager beatmaps, OsuConfigManager osuConfig)
|
||||
{
|
||||
@ -61,7 +70,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
|
||||
button.Action = () =>
|
||||
{
|
||||
switch (State.Value)
|
||||
switch (DownloadTracker.State.Value)
|
||||
{
|
||||
case DownloadState.Downloading:
|
||||
case DownloadState.Importing:
|
||||
@ -71,13 +80,13 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
case DownloadState.LocallyAvailable:
|
||||
Predicate<BeatmapInfo> findPredicate = null;
|
||||
if (SelectedBeatmap.Value != null)
|
||||
findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineBeatmapID;
|
||||
findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineID;
|
||||
|
||||
game?.PresentBeatmap(BeatmapSet.Value, findPredicate);
|
||||
game?.PresentBeatmap(beatmapSet, findPredicate);
|
||||
break;
|
||||
|
||||
default:
|
||||
beatmaps.Download(BeatmapSet.Value, noVideoSetting.Value);
|
||||
beatmaps.Download(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }, noVideoSetting.Value);
|
||||
break;
|
||||
}
|
||||
};
|
||||
@ -92,7 +101,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
break;
|
||||
|
||||
default:
|
||||
if (BeatmapSet.Value?.OnlineInfo?.Availability.DownloadDisabled ?? false)
|
||||
if ((beatmapSet as IBeatmapSetOnlineInfo)?.Availability.DownloadDisabled == true)
|
||||
{
|
||||
button.Enabled.Value = false;
|
||||
button.TooltipText = "this beatmap is currently not available for download.";
|
||||
@ -102,5 +111,11 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
FinishTransforms(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@ -12,13 +13,22 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
public class DownloadProgressBar : BeatmapDownloadTrackingComposite
|
||||
public class DownloadProgressBar : CompositeDrawable
|
||||
{
|
||||
private readonly ProgressBar progressBar;
|
||||
private readonly BeatmapDownloadTracker downloadTracker;
|
||||
|
||||
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
|
||||
: base(beatmapSet)
|
||||
public DownloadProgressBar(IBeatmapSetInfo beatmapSet)
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
progressBar = new ProgressBar(false)
|
||||
{
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
},
|
||||
downloadTracker = new BeatmapDownloadTracker(beatmapSet),
|
||||
};
|
||||
AddInternal(progressBar = new ProgressBar(false)
|
||||
{
|
||||
Height = 0,
|
||||
@ -34,9 +44,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
progressBar.FillColour = colours.Blue;
|
||||
progressBar.BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
progressBar.Current = Progress;
|
||||
progressBar.Current.BindTarget = downloadTracker.Progress;
|
||||
|
||||
State.BindValueChanged(state =>
|
||||
downloadTracker.State.BindValueChanged(state =>
|
||||
{
|
||||
switch (state.NewValue)
|
||||
{
|
||||
|
@ -9,11 +9,11 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
protected override PlayButton PlayButton => playButton;
|
||||
protected override Box PreviewBar => progressBar;
|
||||
|
||||
public GridBeatmapPanel(BeatmapSetInfo beatmap)
|
||||
public GridBeatmapPanel(APIBeatmapSet beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
Width = 380;
|
||||
@ -84,7 +84,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new RomanisableString(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
|
||||
Text = new RomanisableString(SetInfo.TitleUnicode, SetInfo.Title),
|
||||
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true)
|
||||
},
|
||||
}
|
||||
@ -97,7 +97,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
|
||||
Text = new RomanisableString(SetInfo.ArtistUnicode, SetInfo.Artist),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
|
||||
}
|
||||
}
|
||||
@ -145,7 +145,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
d.AutoSizeAxes = Axes.Both;
|
||||
d.AddText("mapped by ", t => t.Colour = colours.Gray5);
|
||||
d.AddUserLink(SetInfo.Metadata.Author);
|
||||
d.AddUserLink(SetInfo.Author);
|
||||
}),
|
||||
new Container
|
||||
{
|
||||
@ -155,11 +155,11 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = SetInfo.Metadata.Source,
|
||||
Text = SetInfo.Source,
|
||||
Font = OsuFont.GetFont(size: 14),
|
||||
Shadow = false,
|
||||
Colour = colours.Gray5,
|
||||
Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
|
||||
Alpha = string.IsNullOrEmpty(SetInfo.Source) ? 0f : 1f,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -193,8 +193,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
Margin = new MarginPadding { Top = vertical_padding, Right = vertical_padding },
|
||||
Children = new[]
|
||||
{
|
||||
new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.OnlineInfo?.PlayCount ?? 0),
|
||||
new Statistic(FontAwesome.Solid.Heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
|
||||
new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.PlayCount),
|
||||
new Statistic(FontAwesome.Solid.Heart, SetInfo.FavouriteCount),
|
||||
},
|
||||
},
|
||||
statusContainer = new FillFlowContainer
|
||||
@ -211,7 +211,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
},
|
||||
});
|
||||
|
||||
if (SetInfo.OnlineInfo?.HasExplicitContent ?? false)
|
||||
if (SetInfo.HasExplicitContent)
|
||||
{
|
||||
titleContainer.Add(new ExplicitContentBeatmapPill
|
||||
{
|
||||
@ -221,7 +221,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
});
|
||||
}
|
||||
|
||||
if (SetInfo.OnlineInfo?.TrackId != null)
|
||||
if (SetInfo.TrackId != null)
|
||||
{
|
||||
artistContainer.Add(new FeaturedArtistBeatmapPill
|
||||
{
|
||||
@ -231,12 +231,12 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
});
|
||||
}
|
||||
|
||||
if (SetInfo.OnlineInfo?.HasVideo ?? false)
|
||||
if (SetInfo.HasVideo)
|
||||
{
|
||||
statusContainer.Add(new IconPill(FontAwesome.Solid.Film));
|
||||
}
|
||||
|
||||
if (SetInfo.OnlineInfo?.HasStoryboard ?? false)
|
||||
if (SetInfo.HasStoryboard)
|
||||
{
|
||||
statusContainer.Add(new IconPill(FontAwesome.Solid.Image));
|
||||
}
|
||||
@ -246,7 +246,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
AutoSizeAxes = Axes.Both,
|
||||
TextSize = 12,
|
||||
TextPadding = new MarginPadding { Horizontal = 10, Vertical = 5 },
|
||||
Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None,
|
||||
Status = SetInfo.Status,
|
||||
});
|
||||
|
||||
PreviewPlaying.ValueChanged += _ => updateStatusContainer();
|
||||
|
@ -9,11 +9,11 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -37,7 +37,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
protected override PlayButton PlayButton => playButton;
|
||||
protected override Box PreviewBar => progressBar;
|
||||
|
||||
public ListBeatmapPanel(BeatmapSetInfo beatmap)
|
||||
public ListBeatmapPanel(APIBeatmapSet beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -107,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new RomanisableString(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
|
||||
Text = new RomanisableString(SetInfo.TitleUnicode, SetInfo.Title),
|
||||
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true)
|
||||
},
|
||||
}
|
||||
@ -120,7 +120,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
|
||||
Text = new RomanisableString(SetInfo.ArtistUnicode, SetInfo.Artist),
|
||||
Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true)
|
||||
},
|
||||
},
|
||||
@ -182,8 +182,8 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.OnlineInfo?.PlayCount ?? 0),
|
||||
new Statistic(FontAwesome.Solid.Heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
|
||||
new Statistic(FontAwesome.Solid.PlayCircle, SetInfo.PlayCount),
|
||||
new Statistic(FontAwesome.Solid.Heart, SetInfo.FavouriteCount),
|
||||
new LinkFlowContainer(s =>
|
||||
{
|
||||
s.Shadow = false;
|
||||
@ -197,15 +197,15 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
d.AutoSizeAxes = Axes.Both;
|
||||
d.AddText("mapped by ");
|
||||
d.AddUserLink(SetInfo.Metadata.Author);
|
||||
d.AddUserLink(SetInfo.Author);
|
||||
}),
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = SetInfo.Metadata.Source,
|
||||
Text = SetInfo.Source,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Font = OsuFont.GetFont(size: 14),
|
||||
Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
|
||||
Alpha = string.IsNullOrEmpty(SetInfo.Source) ? 0f : 1f,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -225,7 +225,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
},
|
||||
});
|
||||
|
||||
if (SetInfo.OnlineInfo?.HasExplicitContent ?? false)
|
||||
if (SetInfo.HasExplicitContent)
|
||||
{
|
||||
titleContainer.Add(new ExplicitContentBeatmapPill
|
||||
{
|
||||
@ -235,7 +235,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
});
|
||||
}
|
||||
|
||||
if (SetInfo.OnlineInfo?.TrackId != null)
|
||||
if (SetInfo.TrackId != null)
|
||||
{
|
||||
artistContainer.Add(new FeaturedArtistBeatmapPill
|
||||
{
|
||||
@ -245,12 +245,12 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
});
|
||||
}
|
||||
|
||||
if (SetInfo.OnlineInfo?.HasVideo ?? false)
|
||||
if (SetInfo.HasVideo)
|
||||
{
|
||||
statusContainer.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
|
||||
}
|
||||
|
||||
if (SetInfo.OnlineInfo?.HasStoryboard ?? false)
|
||||
if (SetInfo.HasStoryboard)
|
||||
{
|
||||
statusContainer.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) });
|
||||
}
|
||||
@ -260,7 +260,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
AutoSizeAxes = Axes.Both,
|
||||
TextSize = 12,
|
||||
TextPadding = new MarginPadding { Horizontal = 10, Vertical = 4 },
|
||||
Status = SetInfo.OnlineInfo?.Status ?? BeatmapSetOnlineStatus.None,
|
||||
Status = SetInfo.Status,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -24,9 +24,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
|
||||
public PreviewTrack Preview { get; private set; }
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
get => beatmapSet;
|
||||
set
|
||||
@ -66,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
}
|
||||
}
|
||||
|
||||
public PlayButton(BeatmapSetInfo setInfo = null)
|
||||
public PlayButton(APIBeatmapSet setInfo = null)
|
||||
{
|
||||
BeatmapSet = setInfo;
|
||||
AddRange(new Drawable[]
|
||||
|
@ -15,10 +15,10 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapListing;
|
||||
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
@ -136,7 +136,7 @@ namespace osu.Game.Overlays
|
||||
return;
|
||||
}
|
||||
|
||||
var newPanels = searchResult.Results.Select<BeatmapSetInfo, BeatmapPanel>(b => new GridBeatmapPanel(b)
|
||||
var newPanels = searchResult.Results.Select<APIBeatmapSet, BeatmapPanel>(b => new GridBeatmapPanel(b)
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Users.Drawables;
|
||||
using osuTK;
|
||||
@ -16,6 +15,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
@ -26,9 +26,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private UpdateableAvatar avatar;
|
||||
private FillFlowContainer fields;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
get => beatmapSet;
|
||||
set
|
||||
@ -78,30 +78,28 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
avatar.User = BeatmapSet?.Metadata.Author;
|
||||
avatar.User = BeatmapSet?.Author;
|
||||
|
||||
fields.Clear();
|
||||
if (BeatmapSet == null)
|
||||
return;
|
||||
|
||||
var online = BeatmapSet.OnlineInfo;
|
||||
|
||||
fields.Children = new Drawable[]
|
||||
{
|
||||
new Field("mapped by", BeatmapSet.Metadata.Author, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
|
||||
new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
|
||||
new Field("mapped by", BeatmapSet.Author, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
|
||||
new Field("submitted", BeatmapSet.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
},
|
||||
};
|
||||
|
||||
if (online.Ranked.HasValue)
|
||||
if (BeatmapSet.Ranked.HasValue)
|
||||
{
|
||||
fields.Add(new Field(online.Status.ToString().ToLowerInvariant(), online.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
fields.Add(new Field(BeatmapSet.Status.ToString().ToLowerInvariant(), BeatmapSet.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
}
|
||||
else if (online.LastUpdated.HasValue)
|
||||
else if (BeatmapSet.LastUpdated.HasValue)
|
||||
{
|
||||
fields.Add(new Field("last updated", online.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
fields.Add(new Field("last updated", BeatmapSet.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osuTK;
|
||||
|
||||
@ -23,9 +24,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
private readonly Statistic length, bpm, circleCount, sliderCount;
|
||||
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
get => beatmapSet;
|
||||
set
|
||||
@ -38,9 +39,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
}
|
||||
|
||||
private BeatmapInfo beatmapInfo;
|
||||
private IBeatmapInfo beatmapInfo;
|
||||
|
||||
public BeatmapInfo BeatmapInfo
|
||||
public IBeatmapInfo BeatmapInfo
|
||||
{
|
||||
get => beatmapInfo;
|
||||
set
|
||||
@ -55,7 +56,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
private void updateDisplay()
|
||||
{
|
||||
bpm.Value = BeatmapSet?.OnlineInfo?.BPM.ToLocalisableString(@"0.##") ?? (LocalisableString)"-";
|
||||
bpm.Value = BeatmapSet?.BPM.ToLocalisableString(@"0.##") ?? (LocalisableString)"-";
|
||||
|
||||
if (beatmapInfo == null)
|
||||
{
|
||||
@ -68,8 +69,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
length.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(beatmapInfo.Length).ToFormattedDuration());
|
||||
length.Value = TimeSpan.FromMilliseconds(beatmapInfo.Length).ToFormattedDuration();
|
||||
|
||||
circleCount.Value = beatmapInfo.OnlineInfo.CircleCount.ToLocalisableString(@"N0");
|
||||
sliderCount.Value = beatmapInfo.OnlineInfo.SliderCount.ToLocalisableString(@"N0");
|
||||
var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
|
||||
|
||||
circleCount.Value = (onlineInfo?.CircleCount ?? 0).ToLocalisableString(@"N0");
|
||||
sliderCount.Value = (onlineInfo?.SliderCount ?? 0).ToLocalisableString(@"N0");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,19 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapAvailability : Container
|
||||
{
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
private bool downloadDisabled => BeatmapSet?.OnlineInfo.Availability.DownloadDisabled ?? false;
|
||||
private bool hasExternalLink => !string.IsNullOrEmpty(BeatmapSet?.OnlineInfo.Availability.ExternalLink);
|
||||
private bool downloadDisabled => BeatmapSet?.Availability.DownloadDisabled ?? false;
|
||||
private bool hasExternalLink => !string.IsNullOrEmpty(BeatmapSet?.Availability.ExternalLink);
|
||||
|
||||
private readonly LinkFlowContainer textContainer;
|
||||
|
||||
@ -44,7 +44,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
};
|
||||
}
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
get => beatmapSet;
|
||||
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
textContainer.NewParagraph();
|
||||
textContainer.NewParagraph();
|
||||
textContainer.AddLink("Check here for more information.", BeatmapSet.OnlineInfo.Availability.ExternalLink, creationParameters: t => t.Font = OsuFont.GetFont(size: 10));
|
||||
textContainer.AddLink("Check here for more information.", BeatmapSet.Availability.ExternalLink, creationParameters: t => t.Font = OsuFont.GetFont(size: 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
@ -34,10 +35,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
public readonly DifficultiesContainer Difficulties;
|
||||
|
||||
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
|
||||
private BeatmapSetInfo beatmapSet;
|
||||
public readonly Bindable<APIBeatmap> Beatmap = new Bindable<APIBeatmap>();
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
get => beatmapSet;
|
||||
set
|
||||
@ -164,35 +165,38 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
if (BeatmapSet != null)
|
||||
{
|
||||
Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Where(b => b.Ruleset.Equals(ruleset.Value)).OrderBy(b => b.StarDifficulty).Select(b => new DifficultySelectorButton(b)
|
||||
{
|
||||
State = DifficultySelectorState.NotSelected,
|
||||
OnHovered = beatmap =>
|
||||
{
|
||||
showBeatmap(beatmap);
|
||||
starRating.Text = beatmap.StarDifficulty.ToLocalisableString(@"0.##");
|
||||
starRatingContainer.FadeIn(100);
|
||||
},
|
||||
OnClicked = beatmap => { Beatmap.Value = beatmap; },
|
||||
});
|
||||
Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps
|
||||
.Where(b => b.Ruleset.OnlineID == ruleset.Value?.OnlineID)
|
||||
.OrderBy(b => b.StarRating)
|
||||
.Select(b => new DifficultySelectorButton(b)
|
||||
{
|
||||
State = DifficultySelectorState.NotSelected,
|
||||
OnHovered = beatmap =>
|
||||
{
|
||||
showBeatmap(beatmap);
|
||||
starRating.Text = beatmap.StarRating.ToLocalisableString(@"0.##");
|
||||
starRatingContainer.FadeIn(100);
|
||||
},
|
||||
OnClicked = beatmap => { Beatmap.Value = beatmap; },
|
||||
});
|
||||
}
|
||||
|
||||
starRatingContainer.FadeOut(100);
|
||||
Beatmap.Value = Difficulties.FirstOrDefault()?.BeatmapInfo;
|
||||
plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0;
|
||||
favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0;
|
||||
Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap;
|
||||
plays.Value = BeatmapSet?.PlayCount ?? 0;
|
||||
favourites.Value = BeatmapSet?.FavouriteCount ?? 0;
|
||||
|
||||
updateDifficultyButtons();
|
||||
}
|
||||
|
||||
private void showBeatmap(BeatmapInfo beatmapInfo)
|
||||
private void showBeatmap(IBeatmapInfo beatmapInfo)
|
||||
{
|
||||
version.Text = beatmapInfo?.Version;
|
||||
version.Text = beatmapInfo?.DifficultyName;
|
||||
}
|
||||
|
||||
private void updateDifficultyButtons()
|
||||
{
|
||||
Difficulties.Children.ToList().ForEach(diff => diff.State = diff.BeatmapInfo == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected);
|
||||
Difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected);
|
||||
}
|
||||
|
||||
public class DifficultiesContainer : FillFlowContainer<DifficultySelectorButton>
|
||||
@ -216,10 +220,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly Box backgroundBox;
|
||||
private readonly DifficultyIcon icon;
|
||||
|
||||
public readonly BeatmapInfo BeatmapInfo;
|
||||
public readonly APIBeatmap Beatmap;
|
||||
|
||||
public Action<BeatmapInfo> OnHovered;
|
||||
public Action<BeatmapInfo> OnClicked;
|
||||
public Action<APIBeatmap> OnHovered;
|
||||
public Action<APIBeatmap> OnClicked;
|
||||
public event Action<DifficultySelectorState> StateChanged;
|
||||
|
||||
private DifficultySelectorState state;
|
||||
@ -241,9 +245,9 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
}
|
||||
}
|
||||
|
||||
public DifficultySelectorButton(BeatmapInfo beatmapInfo)
|
||||
public DifficultySelectorButton(APIBeatmap beatmapInfo)
|
||||
{
|
||||
BeatmapInfo = beatmapInfo;
|
||||
Beatmap = beatmapInfo;
|
||||
Size = new Vector2(size);
|
||||
Margin = new MarginPadding { Horizontal = tile_spacing / 2 };
|
||||
|
||||
@ -273,7 +277,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
fadeIn();
|
||||
OnHovered?.Invoke(BeatmapInfo);
|
||||
OnHovered?.Invoke(Beatmap);
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
@ -286,7 +290,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
OnClicked?.Invoke(BeatmapInfo);
|
||||
OnClicked?.Invoke(Beatmap);
|
||||
return base.OnClick(e);
|
||||
}
|
||||
|
||||
|
@ -3,17 +3,17 @@
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapRulesetSelector : OverlayRulesetSelector
|
||||
{
|
||||
private readonly Bindable<BeatmapSetInfo> beatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
private readonly Bindable<APIBeatmapSet> beatmapSet = new Bindable<APIBeatmapSet>();
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
public APIBeatmapSet BeatmapSet
|
||||
{
|
||||
get => beatmapSet.Value;
|
||||
set
|
||||
|
@ -1,22 +1,22 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapRulesetTabItem : OverlayRulesetTabItem
|
||||
{
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
public readonly Bindable<APIBeatmapSet> BeatmapSet = new Bindable<APIBeatmapSet>();
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
@ -64,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
BeatmapSet.BindValueChanged(setInfo =>
|
||||
{
|
||||
int beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0;
|
||||
int beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.OnlineID == Value.OnlineID) ?? 0;
|
||||
|
||||
count.Text = beatmapsCount.ToString();
|
||||
countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0);
|
||||
|
@ -6,7 +6,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Resources.Localisation.Web;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
public class BeatmapSetHeader : OverlayHeader
|
||||
{
|
||||
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||
public readonly Bindable<APIBeatmapSet> BeatmapSet = new Bindable<APIBeatmapSet>();
|
||||
|
||||
public BeatmapSetHeaderContent HeaderContent { get; private set; }
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user