Merge branch 'master' into ctb-relax

This commit is contained in:
Dean Herbert 2019-12-04 23:35:55 +09:00 committed by GitHub
commit 15ee65b8e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 509 additions and 390 deletions

View File

@ -1,5 +1,6 @@
M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead. M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead. M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead. M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead.
M:System.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead.
T:System.IComparable;Don't use non-generic IComparable. Use generic version instead. T:System.IComparable;Don't use non-generic IComparable. Use generic version instead.
M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText. M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.

View File

@ -16,7 +16,7 @@
<EmbeddedResource Include="Resources\**\*.*" /> <EmbeddedResource Include="Resources\**\*.*" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Code Analysis"> <ItemGroup Label="Code Analysis">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="2.9.7" PrivateAssets="All" /> <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="2.9.8" PrivateAssets="All" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" /> <AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Documentation"> <PropertyGroup Label="Documentation">

View File

@ -34,12 +34,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{ {
mods = Score.Mods; mods = Score.Mods;
var legacyScore = Score as LegacyScoreInfo; fruitsHit = Score?.GetCount300() ?? Score.Statistics[HitResult.Perfect];
ticksHit = Score?.GetCount100() ?? 0;
fruitsHit = legacyScore?.Count300 ?? Score.Statistics[HitResult.Perfect]; tinyTicksHit = Score?.GetCount50() ?? 0;
ticksHit = legacyScore?.Count100 ?? 0; tinyTicksMissed = Score?.GetCountKatu() ?? 0;
tinyTicksHit = legacyScore?.Count50 ?? 0;
tinyTicksMissed = legacyScore?.CountKatu ?? 0;
misses = Score.Statistics[HitResult.Miss]; misses = Score.Statistics[HitResult.Miss];
// Don't count scores made with supposedly unranked mods // Don't count scores made with supposedly unranked mods

View File

@ -37,12 +37,12 @@ namespace osu.Game.Rulesets.Mania.Difficulty
{ {
mods = Score.Mods; mods = Score.Mods;
scaledScore = Score.TotalScore; scaledScore = Score.TotalScore;
countPerfect = Convert.ToInt32(Score.Statistics[HitResult.Perfect]); countPerfect = Score.Statistics[HitResult.Perfect];
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]); countGreat = Score.Statistics[HitResult.Great];
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]); countGood = Score.Statistics[HitResult.Good];
countOk = Convert.ToInt32(Score.Statistics[HitResult.Ok]); countOk = Score.Statistics[HitResult.Ok];
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]); countMeh = Score.Statistics[HitResult.Meh];
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]); countMiss = Score.Statistics[HitResult.Miss];
if (mods.Any(m => !m.Ranked)) if (mods.Any(m => !m.Ranked))
return 0; return 0;

View File

@ -45,10 +45,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
mods = Score.Mods; mods = Score.Mods;
accuracy = Score.Accuracy; accuracy = Score.Accuracy;
scoreMaxCombo = Score.MaxCombo; scoreMaxCombo = Score.MaxCombo;
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]); countGreat = Score.Statistics[HitResult.Great];
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]); countGood = Score.Statistics[HitResult.Good];
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]); countMeh = Score.Statistics[HitResult.Meh];
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]); countMiss = Score.Statistics[HitResult.Miss];
// Don't count scores made with supposedly unranked mods // Don't count scores made with supposedly unranked mods
if (mods.Any(m => !m.Ranked)) if (mods.Any(m => !m.Ranked))

View File

@ -31,10 +31,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
{ {
mods = Score.Mods; mods = Score.Mods;
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]); countGreat = Score.Statistics[HitResult.Great];
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]); countGood = Score.Statistics[HitResult.Good];
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]); countMeh = Score.Statistics[HitResult.Meh];
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]); countMiss = Score.Statistics[HitResult.Miss];
// Don't count scores made with supposedly unranked mods // Don't count scores made with supposedly unranked mods
if (mods.Any(m => !m.Ranked)) if (mods.Any(m => !m.Ranked))

View File

@ -0,0 +1,73 @@
// 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.Scoring;
namespace osu.Game.Tests.Scores.IO
{
[TestFixture]
public class TestScoreEquality
{
[Test]
public void TestNonMatchingByReference()
{
ScoreInfo score1 = new ScoreInfo();
ScoreInfo score2 = new ScoreInfo();
Assert.That(score1, Is.Not.EqualTo(score2));
}
[Test]
public void TestMatchingByReference()
{
ScoreInfo score = new ScoreInfo();
Assert.That(score, Is.EqualTo(score));
}
[Test]
public void TestNonMatchingByPrimaryKey()
{
ScoreInfo score1 = new ScoreInfo { ID = 1 };
ScoreInfo score2 = new ScoreInfo { ID = 2 };
Assert.That(score1, Is.Not.EqualTo(score2));
}
[Test]
public void TestMatchingByPrimaryKey()
{
ScoreInfo score1 = new ScoreInfo { ID = 1 };
ScoreInfo score2 = new ScoreInfo { ID = 1 };
Assert.That(score1, Is.EqualTo(score2));
}
[Test]
public void TestNonMatchingByHash()
{
ScoreInfo score1 = new ScoreInfo { Hash = "a" };
ScoreInfo score2 = new ScoreInfo { Hash = "b" };
Assert.That(score1, Is.Not.EqualTo(score2));
}
[Test]
public void TestMatchingByHash()
{
ScoreInfo score1 = new ScoreInfo { Hash = "a" };
ScoreInfo score2 = new ScoreInfo { Hash = "a" };
Assert.That(score1, Is.EqualTo(score2));
}
[Test]
public void TestNonMatchingByNull()
{
ScoreInfo score = new ScoreInfo();
Assert.That(score, Is.Not.EqualTo(null));
}
}
}

View File

@ -209,9 +209,10 @@ namespace osu.Game.Tests.Visual.Background
public void TransitionTest() public void TransitionTest()
{ {
performFullSetup(); performFullSetup();
var results = new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } }); FadeAccessibleResults results = null;
AddStep("Transition to Results", () => player.Push(results)); AddStep("Transition to Results", () => player.Push(results =
AddUntilStep("Wait for results is current", results.IsCurrentScreen); new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } })));
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
waitForDim(); waitForDim();
AddAssert("Screen is undimmed, original background retained", () => AddAssert("Screen is undimmed, original background retained", () =>
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect()); songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect());

View File

@ -5,11 +5,12 @@ using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Online; using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Users; using osu.Game.Users;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
using osu.Game.Screens.Ranking.Pages; using osu.Game.Screens.Ranking.Pages;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -17,6 +18,9 @@ namespace osu.Game.Tests.Visual.Gameplay
[TestFixture] [TestFixture]
public class TestSceneReplayDownloadButton : OsuTestScene public class TestSceneReplayDownloadButton : OsuTestScene
{ {
[Resolved]
private RulesetStore rulesets { get; set; }
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(ReplayDownloadButton) typeof(ReplayDownloadButton)
@ -49,16 +53,15 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
return new APILegacyScoreInfo return new APILegacyScoreInfo
{ {
ID = 1,
OnlineScoreID = 2553163309, OnlineScoreID = 2553163309,
Ruleset = new OsuRuleset().RulesetInfo, OnlineRulesetID = 0,
Replay = replayAvailable, Replay = replayAvailable,
User = new User User = new User
{ {
Id = 39828, Id = 39828,
Username = @"WubWoofWolf", Username = @"WubWoofWolf",
} }
}; }.CreateScoreInfo(rulesets);
} }
private class TestReplayDownloadButton : ReplayDownloadButton private class TestReplayDownloadButton : ReplayDownloadButton

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
@ -9,9 +9,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores; using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Users; using osu.Game.Users;
using osuTK.Graphics; using osuTK.Graphics;
@ -66,12 +64,12 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"ES", FlagName = @"ES",
}, },
}, },
Mods = new Mod[] Mods = new[]
{ {
new OsuModDoubleTime(), new OsuModDoubleTime().Acronym,
new OsuModHidden(), new OsuModHidden().Acronym,
new OsuModFlashlight(), new OsuModFlashlight().Acronym,
new OsuModHardRock(), new OsuModHardRock().Acronym,
}, },
Rank = ScoreRank.XH, Rank = ScoreRank.XH,
PP = 200, PP = 200,
@ -91,11 +89,11 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"BR", FlagName = @"BR",
}, },
}, },
Mods = new Mod[] Mods = new[]
{ {
new OsuModDoubleTime(), new OsuModDoubleTime().Acronym,
new OsuModHidden(), new OsuModHidden().Acronym,
new OsuModFlashlight(), new OsuModFlashlight().Acronym,
}, },
Rank = ScoreRank.S, Rank = ScoreRank.S,
PP = 190, PP = 190,
@ -115,10 +113,10 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"JP", FlagName = @"JP",
}, },
}, },
Mods = new Mod[] Mods = new[]
{ {
new OsuModDoubleTime(), new OsuModDoubleTime().Acronym,
new OsuModHidden(), new OsuModHidden().Acronym,
}, },
Rank = ScoreRank.B, Rank = ScoreRank.B,
PP = 180, PP = 180,
@ -138,9 +136,9 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"CA", FlagName = @"CA",
}, },
}, },
Mods = new Mod[] Mods = new[]
{ {
new OsuModDoubleTime(), new OsuModDoubleTime().Acronym,
}, },
Rank = ScoreRank.C, Rank = ScoreRank.C,
PP = 170, PP = 170,
@ -208,12 +206,12 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"ES", FlagName = @"ES",
}, },
}, },
Mods = new Mod[] Mods = new[]
{ {
new OsuModDoubleTime(), new OsuModDoubleTime().Acronym,
new OsuModHidden(), new OsuModHidden().Acronym,
new OsuModFlashlight(), new OsuModFlashlight().Acronym,
new OsuModHardRock(), new OsuModHardRock().Acronym,
}, },
Rank = ScoreRank.XH, Rank = ScoreRank.XH,
PP = 200, PP = 200,
@ -226,10 +224,13 @@ namespace osu.Game.Tests.Visual.Online
foreach (var s in allScores.Scores) foreach (var s in allScores.Scores)
{ {
s.Statistics.Add(HitResult.Great, RNG.Next(2000)); s.Statistics = new Dictionary<string, int>
s.Statistics.Add(HitResult.Good, RNG.Next(2000)); {
s.Statistics.Add(HitResult.Meh, RNG.Next(2000)); { "count_300", RNG.Next(2000) },
s.Statistics.Add(HitResult.Miss, RNG.Next(2000)); { "count_100", RNG.Next(2000) },
{ "count_50", RNG.Next(2000) },
{ "count_miss", RNG.Next(2000) }
};
} }
AddStep("Load all scores", () => AddStep("Load all scores", () =>

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards; using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Leaderboards;
@ -62,7 +61,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
User = new User User = new User
{ {
Id = 6602580, Id = 6602580,

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics.Shapes;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select.Leaderboards; using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users; using osu.Game.Users;
@ -52,7 +51,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1, Accuracy = 1,
MaxCombo = 244, MaxCombo = 244,
TotalScore = 1707827, TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
User = new User User = new User
{ {
Id = 6602580, Id = 6602580,

View File

@ -228,7 +228,7 @@ namespace osu.Game.Tournament
if (b.BeatmapInfo == null && b.ID > 0) if (b.BeatmapInfo == null && b.ID > 0)
{ {
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID }); var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
req.Perform(API); API.Perform(req);
b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore); b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);
addedInfo = true; addedInfo = true;

View File

@ -398,7 +398,7 @@ namespace osu.Game.Beatmaps
try try
{ {
// intentionally blocking to limit web request concurrency // intentionally blocking to limit web request concurrency
req.Perform(api); api.Perform(req);
var res = req.Result; var res = req.Result;

View File

@ -25,6 +25,6 @@ namespace osu.Game.Beatmaps.ControlPoints
/// <returns>Whether equivalent.</returns> /// <returns>Whether equivalent.</returns>
public abstract bool EquivalentTo(ControlPoint other); public abstract bool EquivalentTo(ControlPoint other);
public bool Equals(ControlPoint other) => Time.Equals(other?.Time) && EquivalentTo(other); public bool Equals(ControlPoint other) => Time == other?.Time && EquivalentTo(other);
} }
} }

View File

@ -99,17 +99,7 @@ namespace osu.Game.Database
currentDownloads.Add(request); currentDownloads.Add(request);
PostNotification?.Invoke(notification); PostNotification?.Invoke(notification);
Task.Factory.StartNew(() => api.PerformAsync(request);
{
try
{
request.Perform(api);
}
catch (Exception error)
{
triggerFailure(error);
}
}, TaskCreationOptions.LongRunning);
DownloadBegan?.Invoke(request); DownloadBegan?.Invoke(request);
return true; return true;

View File

@ -67,33 +67,21 @@ namespace osu.Game.Graphics.Containers
// receive input outside our bounds so we can trigger a close event on ourselves. // receive input outside our bounds so we can trigger a close event on ourselves.
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceivePositionalInputAt(screenSpacePos);
protected override bool OnClick(ClickEvent e) private bool closeOnMouseUp;
{
if (!base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition))
Hide();
return base.OnClick(e); protected override bool OnMouseDown(MouseDownEvent e)
{
closeOnMouseUp = !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition);
return base.OnMouseDown(e);
} }
private bool closeOnDragEnd; protected override bool OnMouseUp(MouseUpEvent e)
protected override bool OnDragStart(DragStartEvent e)
{ {
if (!base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition)) if (closeOnMouseUp && !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition))
closeOnDragEnd = true;
return base.OnDragStart(e);
}
protected override bool OnDragEnd(DragEndEvent e)
{
if (closeOnDragEnd)
{
Hide(); Hide();
closeOnDragEnd = false;
}
return base.OnDragEnd(e); return base.OnMouseUp(e);
} }
public virtual bool OnPressed(GlobalAction action) public virtual bool OnPressed(GlobalAction action)

View File

@ -151,18 +151,18 @@ namespace osu.Game.Graphics.UserInterface
private void updateTooltipText(T value) private void updateTooltipText(T value)
{ {
if (CurrentNumber.IsInteger) if (CurrentNumber.IsInteger)
TooltipText = ((int)Convert.ChangeType(value, typeof(int))).ToString("N0"); TooltipText = value.ToInt32(NumberFormatInfo.InvariantInfo).ToString("N0");
else else
{ {
double floatValue = (double)Convert.ChangeType(value, typeof(double)); double floatValue = value.ToDouble(NumberFormatInfo.InvariantInfo);
double floatMinValue = (double)Convert.ChangeType(CurrentNumber.MinValue, typeof(double)); double floatMinValue = CurrentNumber.MinValue.ToDouble(NumberFormatInfo.InvariantInfo);
double floatMaxValue = (double)Convert.ChangeType(CurrentNumber.MaxValue, typeof(double)); double floatMaxValue = CurrentNumber.MaxValue.ToDouble(NumberFormatInfo.InvariantInfo);
if (floatMaxValue == 1 && floatMinValue >= -1) if (floatMaxValue == 1 && floatMinValue >= -1)
TooltipText = floatValue.ToString("P0"); TooltipText = floatValue.ToString("P0");
else else
{ {
var decimalPrecision = normalise((decimal)Convert.ChangeType(CurrentNumber.Precision, typeof(decimal)), max_decimal_digits); var decimalPrecision = normalise(CurrentNumber.Precision.ToDecimal(NumberFormatInfo.InvariantInfo), max_decimal_digits);
// Find the number of significant digits (we could have less than 5 after normalize()) // Find the number of significant digits (we could have less than 5 after normalize())
var significantDigits = findPrecision(decimalPrecision); var significantDigits = findPrecision(decimalPrecision);

View File

@ -35,7 +35,7 @@ namespace osu.Game.Graphics.UserInterface
public override bool OnPressed(PlatformAction action) public override bool OnPressed(PlatformAction action)
{ {
// Shift+delete is handled via PlatformAction on macOS. this is not so useful in the context of a SearchTextBox // Shift+delete is handled via PlatformAction on macOS. this is not so useful in the context of a SearchTextBox
// as we do not allow arrow key navigation in the first place (ie. the care should always be at the end of text) // as we do not allow arrow key navigation in the first place (ie. the caret should always be at the end of text)
// Avoid handling it here to allow other components to potentially consume the shortcut. // Avoid handling it here to allow other components to potentially consume the shortcut.
if (action.ActionType == PlatformActionType.CharNext && action.ActionMethod == PlatformActionMethod.Delete) if (action.ActionType == PlatformActionType.CharNext && action.ActionMethod == PlatformActionMethod.Delete)
return false; return false;

View File

@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -198,6 +199,22 @@ namespace osu.Game.Online.API
} }
} }
public void Perform(APIRequest request)
{
try
{
request.Perform(this);
}
catch (Exception e)
{
// todo: fix exception handling
request.Fail(e);
}
}
public Task PerformAsync(APIRequest request) =>
Task.Factory.StartNew(() => Perform(request), TaskCreationOptions.LongRunning);
public void Login(string username, string password) public void Login(string username, string password)
{ {
Debug.Assert(State == APIState.Offline); Debug.Assert(State == APIState.Offline);

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Users; using osu.Game.Users;
@ -56,6 +57,10 @@ namespace osu.Game.Online.API
{ {
} }
public void Perform(APIRequest request) { }
public Task PerformAsync(APIRequest request) => Task.CompletedTask;
public void Register(IOnlineComponent component) public void Register(IOnlineComponent component)
{ {
Scheduler.Add(delegate { components.Add(component); }); Scheduler.Add(delegate { components.Add(component); });

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Threading.Tasks;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Game.Users; using osu.Game.Users;
@ -42,6 +43,24 @@ namespace osu.Game.Online.API
/// <param name="request">The request to perform.</param> /// <param name="request">The request to perform.</param>
void Queue(APIRequest request); void Queue(APIRequest request);
/// <summary>
/// Perform a request immediately, bypassing any API state checks.
/// </summary>
/// <remarks>
/// Can be used to run requests as a guest user.
/// </remarks>
/// <param name="request">The request to perform.</param>
void Perform(APIRequest request);
/// <summary>
/// Perform a request immediately, bypassing any API state checks.
/// </summary>
/// <remarks>
/// Can be used to run requests as a guest user.
/// </remarks>
/// <param name="request">The request to perform.</param>
Task PerformAsync(APIRequest request);
/// <summary> /// <summary>
/// Register a component to receive state changes. /// Register a component to receive state changes.
/// </summary> /// </summary>

View File

@ -9,6 +9,7 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using System.Text; using System.Text;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
namespace osu.Game.Online.API.Requests namespace osu.Game.Online.API.Requests
{ {
@ -37,10 +38,12 @@ namespace osu.Game.Online.API.Requests
private void onSuccess(APILegacyScores r) private void onSuccess(APILegacyScores r)
{ {
Debug.Assert(ruleset.ID != null, "ruleset.ID != null");
foreach (APILegacyScoreInfo score in r.Scores) foreach (APILegacyScoreInfo score in r.Scores)
{ {
score.Beatmap = beatmap; score.Beatmap = beatmap;
score.Ruleset = ruleset; score.OnlineRulesetID = ruleset.ID.Value;
} }
var userScore = r.UserScore; var userScore = r.UserScore;
@ -48,7 +51,7 @@ namespace osu.Game.Online.API.Requests
if (userScore != null) if (userScore != null)
{ {
userScore.Score.Beatmap = beatmap; userScore.Score.Beatmap = beatmap;
userScore.Score.Ruleset = ruleset; userScore.Score.OnlineRulesetID = ruleset.ID.Value;
} }
} }

View File

@ -5,56 +5,106 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy; using osu.Game.Scoring.Legacy;
using osu.Game.Users; using osu.Game.Users;
namespace osu.Game.Online.API.Requests.Responses namespace osu.Game.Online.API.Requests.Responses
{ {
public class APILegacyScoreInfo : LegacyScoreInfo public class APILegacyScoreInfo
{ {
[JsonProperty(@"score")] public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
private int totalScore
{ {
set => TotalScore = value; var ruleset = rulesets.GetRuleset(OnlineRulesetID);
var mods = Mods != null ? ruleset.CreateInstance().GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
var scoreInfo = new ScoreInfo
{
TotalScore = TotalScore,
MaxCombo = MaxCombo,
User = User,
Accuracy = Accuracy,
OnlineScoreID = OnlineScoreID,
Date = Date,
PP = PP,
Beatmap = Beatmap,
RulesetID = OnlineRulesetID,
Hash = "online", // todo: temporary?
Rank = Rank,
Ruleset = ruleset,
Mods = mods,
};
if (Statistics != null)
{
foreach (var kvp in Statistics)
{
switch (kvp.Key)
{
case @"count_geki":
scoreInfo.SetCountGeki(kvp.Value);
break;
case @"count_300":
scoreInfo.SetCount300(kvp.Value);
break;
case @"count_katu":
scoreInfo.SetCountKatu(kvp.Value);
break;
case @"count_100":
scoreInfo.SetCount100(kvp.Value);
break;
case @"count_50":
scoreInfo.SetCount50(kvp.Value);
break;
case @"count_miss":
scoreInfo.SetCountMiss(kvp.Value);
break;
}
}
}
return scoreInfo;
} }
[JsonProperty(@"score")]
public int TotalScore { get; set; }
[JsonProperty(@"max_combo")] [JsonProperty(@"max_combo")]
private int maxCombo public int MaxCombo { get; set; }
{
set => MaxCombo = value;
}
[JsonProperty(@"user")] [JsonProperty(@"user")]
private User user public User User { get; set; }
{
set => User = value;
}
[JsonProperty(@"id")] [JsonProperty(@"id")]
private long onlineScoreID public long OnlineScoreID { get; set; }
{
set => OnlineScoreID = value;
}
[JsonProperty(@"replay")] [JsonProperty(@"replay")]
public bool Replay { get; set; } public bool Replay { get; set; }
[JsonProperty(@"created_at")] [JsonProperty(@"created_at")]
private DateTimeOffset date public DateTimeOffset Date { get; set; }
{
set => Date = value;
}
[JsonProperty(@"beatmap")] [JsonProperty(@"beatmap")]
private BeatmapInfo beatmap public BeatmapInfo Beatmap { get; set; }
{
set => Beatmap = value; [JsonProperty("accuracy")]
} public double Accuracy { get; set; }
[JsonProperty(@"pp")]
public double? PP { get; set; }
[JsonProperty(@"beatmapset")] [JsonProperty(@"beatmapset")]
private BeatmapMetadata metadata public BeatmapMetadata Metadata
{ {
set set
{ {
@ -67,68 +117,16 @@ namespace osu.Game.Online.API.Requests.Responses
} }
[JsonProperty(@"statistics")] [JsonProperty(@"statistics")]
private Dictionary<string, int> jsonStats public Dictionary<string, int> Statistics { get; set; }
{
set
{
foreach (var kvp in value)
{
switch (kvp.Key)
{
case @"count_geki":
CountGeki = kvp.Value;
break;
case @"count_300":
Count300 = kvp.Value;
break;
case @"count_katu":
CountKatu = kvp.Value;
break;
case @"count_100":
Count100 = kvp.Value;
break;
case @"count_50":
Count50 = kvp.Value;
break;
case @"count_miss":
CountMiss = kvp.Value;
break;
default:
continue;
}
}
}
}
[JsonProperty(@"mode_int")] [JsonProperty(@"mode_int")]
public int OnlineRulesetID public int OnlineRulesetID { get; set; }
{
get => RulesetID;
set => RulesetID = value;
}
[JsonProperty(@"mods")] [JsonProperty(@"mods")]
private string[] modStrings { get; set; } public string[] Mods { get; set; }
public override RulesetInfo Ruleset [JsonProperty("rank")]
{ [JsonConverter(typeof(StringEnumConverter))]
get => base.Ruleset; public ScoreRank Rank { get; set; }
set
{
base.Ruleset = value;
if (modStrings != null)
{
// Evaluate the mod string
Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.Acronym)).ToArray();
}
}
}
} }
} }

View File

@ -406,11 +406,11 @@ namespace osu.Game
nextBeatmap?.LoadBeatmapAsync(); nextBeatmap?.LoadBeatmapAsync();
} }
private void currentTrackCompleted() private void currentTrackCompleted() => Schedule(() =>
{ {
if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled) if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled)
musicController.NextTrack(); musicController.NextTrack();
} });
#endregion #endregion

View File

@ -41,6 +41,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
[Resolved] [Resolved]
private IAPIProvider api { get; set; } private IAPIProvider api { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; }
private GetScoresRequest getScoresRequest; private GetScoresRequest getScoresRequest;
protected APILegacyScores Scores protected APILegacyScores Scores
@ -56,16 +59,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
return; return;
} }
scoreTable.Scores = value.Scores; var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList();
scoreTable.Scores = scoreInfos;
scoreTable.Show(); scoreTable.Show();
var topScore = value.Scores.First(); var topScore = scoreInfos.First();
var userScore = value.UserScore; var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
topScoresContainer.Add(new DrawableTopScore(topScore)); topScoresContainer.Add(new DrawableTopScore(topScore));
if (userScore != null && userScore.Score.OnlineScoreID != topScore.OnlineScoreID) if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID)
topScoresContainer.Add(new DrawableTopScore(userScore.Score, userScore.Position)); topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
}); });
} }

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -43,18 +42,7 @@ namespace osu.Game.Overlays.Changelog
}; };
req.Failure += _ => complete = true; req.Failure += _ => complete = true;
// This is done on a separate thread to support cancellation below api.PerformAsync(req);
Task.Run(() =>
{
try
{
req.Perform(api);
}
catch
{
complete = true;
}
});
while (!complete) while (!complete)
{ {

View File

@ -191,15 +191,7 @@ namespace osu.Game.Overlays
tcs.SetResult(false); tcs.SetResult(false);
}; };
try await API.PerformAsync(req);
{
req.Perform(API);
}
catch
{
initialFetchTask = null;
tcs.SetResult(false);
}
await tcs.Task; await tcs.Task;
}); });

View File

@ -16,6 +16,7 @@ using osu.Game.Users;
namespace osu.Game.Overlays.MedalSplash namespace osu.Game.Overlays.MedalSplash
{ {
[LongRunningLoad]
public class DrawableMedal : Container, IStateful<DisplayState> public class DrawableMedal : Container, IStateful<DisplayState>
{ {
private const float scale_when_unlocked = 0.76f; private const float scale_when_unlocked = 0.76f;

View File

@ -12,6 +12,7 @@ using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components namespace osu.Game.Overlays.Profile.Header.Components
{ {
[LongRunningLoad]
public class DrawableBadge : CompositeDrawable, IHasTooltip public class DrawableBadge : CompositeDrawable, IHasTooltip
{ {
public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40); public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40);

View File

@ -19,8 +19,8 @@ namespace osu.Game.Overlays.Profile.Sections
private const int fade_duration = 200; private const int fade_duration = 200;
private Box underscoreLine; private Box underscoreLine;
private readonly Box coloredBackground; private Box coloredBackground;
private readonly Container background; private Container background;
/// <summary> /// <summary>
/// A visual element displayed to the left of <see cref="LeftFlowContainer"/> content. /// A visual element displayed to the left of <see cref="LeftFlowContainer"/> content.
@ -36,6 +36,19 @@ namespace osu.Game.Overlays.Profile.Sections
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = 60; Height = 60;
Content = new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 0.97f,
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
{
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
background = new Container background = new Container
@ -53,21 +66,7 @@ namespace osu.Game.Overlays.Profile.Sections
}, },
Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both } Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
}, },
Content = new Container Content,
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 0.97f,
},
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
{
AddRange(new Drawable[]
{
underscoreLine = new Box underscoreLine = new Box
{ {
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
@ -101,7 +100,7 @@ namespace osu.Game.Overlays.Profile.Sections
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
}, },
}); };
coloredBackground.Colour = underscoreLine.Colour = colour.Gray4; coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
} }

View File

@ -29,14 +29,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
ItemsContainer.Direction = FillDirection.Vertical; ItemsContainer.Direction = FillDirection.Vertical;
} }
protected override void UpdateItems(List<APILegacyScoreInfo> items)
{
foreach (var item in items)
item.Ruleset = Rulesets.GetRuleset(item.RulesetID);
base.UpdateItems(items);
}
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() => protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
@ -45,10 +37,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
switch (type) switch (type)
{ {
default: default:
return new DrawablePerformanceScore(model, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null); return new DrawablePerformanceScore(model.CreateScoreInfo(Rulesets), includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
case ScoreType.Recent: case ScoreType.Recent:
return new DrawableTotalScore(model); return new DrawableTotalScore(model.CreateScoreInfo(Rulesets));
} }
} }
} }

View File

@ -66,11 +66,14 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
}; };
case RecentActivityType.Achievement: case RecentActivityType.Achievement:
return new MedalIcon(activity.Achievement.Slug) return new DelayedLoadWrapper(new MedalIcon(activity.Achievement.Slug)
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
})
{ {
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
Width = 60, Width = 60,
FillMode = FillMode.Fit,
}; };
default: default:

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Textures;
namespace osu.Game.Overlays.Profile.Sections.Recent namespace osu.Game.Overlays.Profile.Sections.Recent
{ {
[LongRunningLoad]
public class MedalIcon : Container public class MedalIcon : Container
{ {
private readonly string slug; private readonly string slug;

View File

@ -273,14 +273,6 @@ namespace osu.Game.Rulesets.Objects
return p0 + (p1 - p0) * (float)w; return p0 + (p1 - p0) * (float)w;
} }
public bool Equals(SliderPath other) public bool Equals(SliderPath other) => ControlPoints.SequenceEqual(other.ControlPoints) && ExpectedDistance == other.ExpectedDistance && Type == other.Type;
{
if (ControlPoints == null && other.ControlPoints != null)
return false;
if (other.ControlPoints == null && ControlPoints != null)
return false;
return ControlPoints.SequenceEqual(other.ControlPoints) && ExpectedDistance.Equals(other.ExpectedDistance) && Type == other.Type;
}
} }
} }

View File

@ -1,118 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring.Legacy
{
public class LegacyScoreInfo : ScoreInfo
{
private int countGeki;
public int CountGeki
{
get => countGeki;
set
{
countGeki = value;
switch (Ruleset?.ID ?? RulesetID)
{
case 3:
Statistics[HitResult.Perfect] = value;
break;
}
}
}
private int count300;
public int Count300
{
get => count300;
set
{
count300 = value;
switch (Ruleset?.ID ?? RulesetID)
{
case 0:
case 1:
case 3:
Statistics[HitResult.Great] = value;
break;
case 2:
Statistics[HitResult.Perfect] = value;
break;
}
}
}
private int countKatu;
public int CountKatu
{
get => countKatu;
set
{
countKatu = value;
switch (Ruleset?.ID ?? RulesetID)
{
case 3:
Statistics[HitResult.Good] = value;
break;
}
}
}
private int count100;
public int Count100
{
get => count100;
set
{
count100 = value;
switch (Ruleset?.ID ?? RulesetID)
{
case 0:
case 1:
Statistics[HitResult.Good] = value;
break;
case 3:
Statistics[HitResult.Ok] = value;
break;
}
}
}
private int count50;
public int Count50
{
get => count50;
set
{
count50 = value;
switch (Ruleset?.ID ?? RulesetID)
{
case 0:
case 3:
Statistics[HitResult.Meh] = value;
break;
}
}
}
public int CountMiss
{
get => Statistics[HitResult.Miss];
set => Statistics[HitResult.Miss] = value;
}
}
}

View File

@ -35,7 +35,7 @@ namespace osu.Game.Scoring.Legacy
using (SerializationReader sr = new SerializationReader(stream)) using (SerializationReader sr = new SerializationReader(stream))
{ {
currentRuleset = GetRuleset(sr.ReadByte()); currentRuleset = GetRuleset(sr.ReadByte());
var scoreInfo = new LegacyScoreInfo { Ruleset = currentRuleset.RulesetInfo }; var scoreInfo = new ScoreInfo { Ruleset = currentRuleset.RulesetInfo };
score.ScoreInfo = scoreInfo; score.ScoreInfo = scoreInfo;
@ -53,12 +53,12 @@ namespace osu.Game.Scoring.Legacy
// MD5Hash // MD5Hash
sr.ReadString(); sr.ReadString();
scoreInfo.Count300 = sr.ReadUInt16(); scoreInfo.SetCount300(sr.ReadUInt16());
scoreInfo.Count100 = sr.ReadUInt16(); scoreInfo.SetCount100(sr.ReadUInt16());
scoreInfo.Count50 = sr.ReadUInt16(); scoreInfo.SetCount50(sr.ReadUInt16());
scoreInfo.CountGeki = sr.ReadUInt16(); scoreInfo.SetCountGeki(sr.ReadUInt16());
scoreInfo.CountKatu = sr.ReadUInt16(); scoreInfo.SetCountKatu(sr.ReadUInt16());
scoreInfo.CountMiss = sr.ReadUInt16(); scoreInfo.SetCountMiss(sr.ReadUInt16());
scoreInfo.TotalScore = sr.ReadInt32(); scoreInfo.TotalScore = sr.ReadInt32();
scoreInfo.MaxCombo = sr.ReadUInt16(); scoreInfo.MaxCombo = sr.ReadUInt16();

View File

@ -0,0 +1,143 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring.Legacy
{
public static class ScoreInfoExtensions
{
public static int? GetCountGeki(this ScoreInfo scoreInfo)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 3:
return scoreInfo.Statistics[HitResult.Perfect];
}
return null;
}
public static void SetCountGeki(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 3:
scoreInfo.Statistics[HitResult.Perfect] = value;
break;
}
}
public static int? GetCount300(this ScoreInfo scoreInfo)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 1:
case 3:
return scoreInfo.Statistics[HitResult.Great];
case 2:
return scoreInfo.Statistics[HitResult.Perfect];
}
return null;
}
public static void SetCount300(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 1:
case 3:
scoreInfo.Statistics[HitResult.Great] = value;
break;
case 2:
scoreInfo.Statistics[HitResult.Perfect] = value;
break;
}
}
public static int? GetCountKatu(this ScoreInfo scoreInfo)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 3:
return scoreInfo.Statistics[HitResult.Good];
}
return null;
}
public static void SetCountKatu(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 3:
scoreInfo.Statistics[HitResult.Good] = value;
break;
}
}
public static int? GetCount100(this ScoreInfo scoreInfo)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 1:
return scoreInfo.Statistics[HitResult.Good];
case 3:
return scoreInfo.Statistics[HitResult.Ok];
}
return null;
}
public static void SetCount100(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 1:
scoreInfo.Statistics[HitResult.Good] = value;
break;
case 3:
scoreInfo.Statistics[HitResult.Ok] = value;
break;
}
}
public static int? GetCount50(this ScoreInfo scoreInfo)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 3:
return scoreInfo.Statistics[HitResult.Meh];
}
return null;
}
public static void SetCount50(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 3:
scoreInfo.Statistics[HitResult.Meh] = value;
break;
}
}
public static int? GetCountMiss(this ScoreInfo scoreInfo) =>
scoreInfo.Statistics[HitResult.Miss];
public static void SetCountMiss(this ScoreInfo scoreInfo, int value) =>
scoreInfo.Statistics[HitResult.Miss] = value;
}
}

View File

@ -183,10 +183,21 @@ namespace osu.Game.Scoring
public override string ToString() => $"{User} playing {Beatmap}"; public override string ToString() => $"{User} playing {Beatmap}";
public bool Equals(ScoreInfo other) => public bool Equals(ScoreInfo other)
other != null {
&& other.OnlineScoreID == OnlineScoreID if (other == null)
&& other.BeatmapInfoID == BeatmapInfoID return false;
&& other.Hash == Hash;
if (ID != 0 && other.ID != 0)
return ID == other.ID;
if (OnlineScoreID.HasValue && other.OnlineScoreID.HasValue)
return OnlineScoreID == other.OnlineScoreID;
if (!string.IsNullOrEmpty(Hash) && !string.IsNullOrEmpty(other.Hash))
return Hash == other.Hash;
return ReferenceEquals(this, other);
}
} }
} }

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online; using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Scoring; using osu.Game.Scoring;
using osuTK; using osuTK;
@ -24,7 +23,7 @@ namespace osu.Game.Screens.Ranking.Pages
if (State.Value == DownloadState.LocallyAvailable) if (State.Value == DownloadState.LocallyAvailable)
return ReplayAvailability.Local; return ReplayAvailability.Local;
if (Model.Value is APILegacyScoreInfo apiScore && apiScore.Replay) if (!string.IsNullOrEmpty(Model.Value.Hash))
return ReplayAvailability.Online; return ReplayAvailability.Online;
return ReplayAvailability.NotAvailable; return ReplayAvailability.NotAvailable;

View File

@ -70,7 +70,10 @@ namespace osu.Game.Screens.Ranking.Pages
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
new UserHeader(Score.User) new DelayedLoadWrapper(new UserHeader(Score.User)
{
RelativeSizeAxes = Axes.Both,
})
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
@ -370,6 +373,7 @@ namespace osu.Game.Screens.Ranking.Pages
} }
} }
[LongRunningLoad]
private class UserHeader : Container private class UserHeader : Container
{ {
private readonly User user; private readonly User user;

View File

@ -79,8 +79,8 @@ namespace osu.Game.Screens.Select
public bool IsUpperInclusive; public bool IsUpperInclusive;
public bool Equals(OptionalRange<T> other) public bool Equals(OptionalRange<T> other)
=> Min.Equals(other.Min) => EqualityComparer<T?>.Default.Equals(Min, other.Min)
&& Max.Equals(other.Max) && EqualityComparer<T?>.Default.Equals(Max, other.Max)
&& IsLowerInclusive.Equals(other.IsLowerInclusive) && IsLowerInclusive.Equals(other.IsLowerInclusive)
&& IsUpperInclusive.Equals(other.IsUpperInclusive); && IsUpperInclusive.Equals(other.IsUpperInclusive);
} }

View File

@ -21,6 +21,9 @@ namespace osu.Game.Screens.Select.Leaderboards
{ {
public Action<ScoreInfo> ScoreSelected; public Action<ScoreInfo> ScoreSelected;
[Resolved]
private RulesetStore rulesets { get; set; }
private BeatmapInfo beatmap; private BeatmapInfo beatmap;
public BeatmapInfo Beatmap public BeatmapInfo Beatmap
@ -172,7 +175,7 @@ namespace osu.Game.Screens.Select.Leaderboards
req.Success += r => req.Success += r =>
{ {
scoresCallback?.Invoke(r.Scores); scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets)));
TopScore = r.UserScore; TopScore = r.UserScore;
}; };

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Threading; using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -10,6 +11,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards; using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets;
using osu.Game.Scoring; using osu.Game.Scoring;
using osuTK; using osuTK;
@ -27,6 +29,9 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override bool StartHidden => true; protected override bool StartHidden => true;
[Resolved]
private RulesetStore rulesets { get; set; }
public UserTopScoreContainer() public UserTopScoreContainer()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -77,9 +82,11 @@ namespace osu.Game.Screens.Select.Leaderboards
if (newScore == null) if (newScore == null)
return; return;
LoadComponentAsync(new LeaderboardScore(newScore.Score, newScore.Position, false) var scoreInfo = newScore.Score.CreateScoreInfo(rulesets);
LoadComponentAsync(new LeaderboardScore(scoreInfo, newScore.Position, false)
{ {
Action = () => ScoreSelected?.Invoke(newScore.Score) Action = () => ScoreSelected?.Invoke(scoreInfo)
}, drawableScore => }, drawableScore =>
{ {
scoreContainer.Child = drawableScore; scoreContainer.Child = drawableScore;

View File

@ -240,6 +240,6 @@ namespace osu.Game.Tests.Beatmaps
set => Objects = value; set => Objects = value;
} }
public virtual bool Equals(ConvertMapping<TConvertValue> other) => StartTime.Equals(other?.StartTime); public virtual bool Equals(ConvertMapping<TConvertValue> other) => StartTime == other?.StartTime;
} }
} }