mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 02:02:53 +08:00
Merge branch 'master' into ctb-relax
This commit is contained in:
commit
15ee65b8e9
@ -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.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.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead.
|
||||
T:System.IComparable;Don't use non-generic IComparable. Use generic version instead.
|
||||
M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.
|
||||
|
@ -16,7 +16,7 @@
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Documentation">
|
||||
|
@ -34,12 +34,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
{
|
||||
mods = Score.Mods;
|
||||
|
||||
var legacyScore = Score as LegacyScoreInfo;
|
||||
|
||||
fruitsHit = legacyScore?.Count300 ?? Score.Statistics[HitResult.Perfect];
|
||||
ticksHit = legacyScore?.Count100 ?? 0;
|
||||
tinyTicksHit = legacyScore?.Count50 ?? 0;
|
||||
tinyTicksMissed = legacyScore?.CountKatu ?? 0;
|
||||
fruitsHit = Score?.GetCount300() ?? Score.Statistics[HitResult.Perfect];
|
||||
ticksHit = Score?.GetCount100() ?? 0;
|
||||
tinyTicksHit = Score?.GetCount50() ?? 0;
|
||||
tinyTicksMissed = Score?.GetCountKatu() ?? 0;
|
||||
misses = Score.Statistics[HitResult.Miss];
|
||||
|
||||
// Don't count scores made with supposedly unranked mods
|
||||
|
@ -37,12 +37,12 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
{
|
||||
mods = Score.Mods;
|
||||
scaledScore = Score.TotalScore;
|
||||
countPerfect = Convert.ToInt32(Score.Statistics[HitResult.Perfect]);
|
||||
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||
countOk = Convert.ToInt32(Score.Statistics[HitResult.Ok]);
|
||||
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||
countPerfect = Score.Statistics[HitResult.Perfect];
|
||||
countGreat = Score.Statistics[HitResult.Great];
|
||||
countGood = Score.Statistics[HitResult.Good];
|
||||
countOk = Score.Statistics[HitResult.Ok];
|
||||
countMeh = Score.Statistics[HitResult.Meh];
|
||||
countMiss = Score.Statistics[HitResult.Miss];
|
||||
|
||||
if (mods.Any(m => !m.Ranked))
|
||||
return 0;
|
||||
|
@ -45,10 +45,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
mods = Score.Mods;
|
||||
accuracy = Score.Accuracy;
|
||||
scoreMaxCombo = Score.MaxCombo;
|
||||
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||
countGreat = Score.Statistics[HitResult.Great];
|
||||
countGood = Score.Statistics[HitResult.Good];
|
||||
countMeh = Score.Statistics[HitResult.Meh];
|
||||
countMiss = Score.Statistics[HitResult.Miss];
|
||||
|
||||
// Don't count scores made with supposedly unranked mods
|
||||
if (mods.Any(m => !m.Ranked))
|
||||
|
@ -31,10 +31,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||
{
|
||||
mods = Score.Mods;
|
||||
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||
countGreat = Score.Statistics[HitResult.Great];
|
||||
countGood = Score.Statistics[HitResult.Good];
|
||||
countMeh = Score.Statistics[HitResult.Meh];
|
||||
countMiss = Score.Statistics[HitResult.Miss];
|
||||
|
||||
// Don't count scores made with supposedly unranked mods
|
||||
if (mods.Any(m => !m.Ranked))
|
||||
|
73
osu.Game.Tests/Scores/IO/TestScoreEquality.cs
Normal file
73
osu.Game.Tests/Scores/IO/TestScoreEquality.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
@ -209,9 +209,10 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void TransitionTest()
|
||||
{
|
||||
performFullSetup();
|
||||
var results = new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } });
|
||||
AddStep("Transition to Results", () => player.Push(results));
|
||||
AddUntilStep("Wait for results is current", results.IsCurrentScreen);
|
||||
FadeAccessibleResults results = null;
|
||||
AddStep("Transition to Results", () => player.Push(results =
|
||||
new FadeAccessibleResults(new ScoreInfo { User = new User { Username = "osu!" } })));
|
||||
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
|
||||
waitForDim();
|
||||
AddAssert("Screen is undimmed, original background retained", () =>
|
||||
songSelect.IsBackgroundUndimmed() && songSelect.IsBackgroundCurrent() && results.IsBlurCorrect());
|
||||
|
@ -5,11 +5,12 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Ranking.Pages;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
@ -17,6 +18,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[TestFixture]
|
||||
public class TestSceneReplayDownloadButton : OsuTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(ReplayDownloadButton)
|
||||
@ -49,16 +53,15 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
return new APILegacyScoreInfo
|
||||
{
|
||||
ID = 1,
|
||||
OnlineScoreID = 2553163309,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
OnlineRulesetID = 0,
|
||||
Replay = replayAvailable,
|
||||
User = new User
|
||||
{
|
||||
Id = 39828,
|
||||
Username = @"WubWoofWolf",
|
||||
}
|
||||
};
|
||||
}.CreateScoreInfo(rulesets);
|
||||
}
|
||||
|
||||
private class TestReplayDownloadButton : ReplayDownloadButton
|
||||
|
@ -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.
|
||||
|
||||
using System;
|
||||
@ -9,9 +9,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Graphics;
|
||||
@ -66,12 +64,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
FlagName = @"ES",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new OsuModFlashlight().Acronym,
|
||||
new OsuModHardRock().Acronym,
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
@ -91,11 +89,11 @@ namespace osu.Game.Tests.Visual.Online
|
||||
FlagName = @"BR",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new OsuModFlashlight().Acronym,
|
||||
},
|
||||
Rank = ScoreRank.S,
|
||||
PP = 190,
|
||||
@ -115,10 +113,10 @@ namespace osu.Game.Tests.Visual.Online
|
||||
FlagName = @"JP",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
},
|
||||
Rank = ScoreRank.B,
|
||||
PP = 180,
|
||||
@ -138,9 +136,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
FlagName = @"CA",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModDoubleTime().Acronym,
|
||||
},
|
||||
Rank = ScoreRank.C,
|
||||
PP = 170,
|
||||
@ -208,12 +206,12 @@ namespace osu.Game.Tests.Visual.Online
|
||||
FlagName = @"ES",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
Mods = new[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
new OsuModHardRock(),
|
||||
new OsuModDoubleTime().Acronym,
|
||||
new OsuModHidden().Acronym,
|
||||
new OsuModFlashlight().Acronym,
|
||||
new OsuModHardRock().Acronym,
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
@ -226,10 +224,13 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
foreach (var s in allScores.Scores)
|
||||
{
|
||||
s.Statistics.Add(HitResult.Great, RNG.Next(2000));
|
||||
s.Statistics.Add(HitResult.Good, RNG.Next(2000));
|
||||
s.Statistics.Add(HitResult.Meh, RNG.Next(2000));
|
||||
s.Statistics.Add(HitResult.Miss, RNG.Next(2000));
|
||||
s.Statistics = new Dictionary<string, int>
|
||||
{
|
||||
{ "count_300", RNG.Next(2000) },
|
||||
{ "count_100", RNG.Next(2000) },
|
||||
{ "count_50", RNG.Next(2000) },
|
||||
{ "count_miss", RNG.Next(2000) }
|
||||
};
|
||||
}
|
||||
|
||||
AddStep("Load all scores", () =>
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
@ -62,7 +61,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
||||
User = new User
|
||||
{
|
||||
Id = 6602580,
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Users;
|
||||
@ -52,7 +51,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
|
||||
User = new User
|
||||
{
|
||||
Id = 6602580,
|
||||
|
@ -228,7 +228,7 @@ namespace osu.Game.Tournament
|
||||
if (b.BeatmapInfo == null && b.ID > 0)
|
||||
{
|
||||
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
|
||||
req.Perform(API);
|
||||
API.Perform(req);
|
||||
b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);
|
||||
|
||||
addedInfo = true;
|
||||
|
@ -398,7 +398,7 @@ namespace osu.Game.Beatmaps
|
||||
try
|
||||
{
|
||||
// intentionally blocking to limit web request concurrency
|
||||
req.Perform(api);
|
||||
api.Perform(req);
|
||||
|
||||
var res = req.Result;
|
||||
|
||||
|
@ -25,6 +25,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// <returns>Whether equivalent.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -99,17 +99,7 @@ namespace osu.Game.Database
|
||||
currentDownloads.Add(request);
|
||||
PostNotification?.Invoke(notification);
|
||||
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
request.Perform(api);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
triggerFailure(error);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
api.PerformAsync(request);
|
||||
|
||||
DownloadBegan?.Invoke(request);
|
||||
return true;
|
||||
|
@ -67,33 +67,21 @@ namespace osu.Game.Graphics.Containers
|
||||
// receive input outside our bounds so we can trigger a close event on ourselves.
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BlockScreenWideMouse || base.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (!base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition))
|
||||
Hide();
|
||||
private bool closeOnMouseUp;
|
||||
|
||||
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 OnDragStart(DragStartEvent e)
|
||||
protected override bool OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
if (!base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition))
|
||||
closeOnDragEnd = true;
|
||||
|
||||
return base.OnDragStart(e);
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
if (closeOnDragEnd)
|
||||
{
|
||||
if (closeOnMouseUp && !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition))
|
||||
Hide();
|
||||
closeOnDragEnd = false;
|
||||
}
|
||||
|
||||
return base.OnDragEnd(e);
|
||||
return base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
public virtual bool OnPressed(GlobalAction action)
|
||||
|
@ -151,18 +151,18 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private void updateTooltipText(T value)
|
||||
{
|
||||
if (CurrentNumber.IsInteger)
|
||||
TooltipText = ((int)Convert.ChangeType(value, typeof(int))).ToString("N0");
|
||||
TooltipText = value.ToInt32(NumberFormatInfo.InvariantInfo).ToString("N0");
|
||||
else
|
||||
{
|
||||
double floatValue = (double)Convert.ChangeType(value, typeof(double));
|
||||
double floatMinValue = (double)Convert.ChangeType(CurrentNumber.MinValue, typeof(double));
|
||||
double floatMaxValue = (double)Convert.ChangeType(CurrentNumber.MaxValue, typeof(double));
|
||||
double floatValue = value.ToDouble(NumberFormatInfo.InvariantInfo);
|
||||
double floatMinValue = CurrentNumber.MinValue.ToDouble(NumberFormatInfo.InvariantInfo);
|
||||
double floatMaxValue = CurrentNumber.MaxValue.ToDouble(NumberFormatInfo.InvariantInfo);
|
||||
|
||||
if (floatMaxValue == 1 && floatMinValue >= -1)
|
||||
TooltipText = floatValue.ToString("P0");
|
||||
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())
|
||||
var significantDigits = findPrecision(decimalPrecision);
|
||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
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
|
||||
// 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.
|
||||
if (action.ActionType == PlatformActionType.CharNext && action.ActionMethod == PlatformActionMethod.Delete)
|
||||
return false;
|
||||
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using osu.Framework.Bindables;
|
||||
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)
|
||||
{
|
||||
Debug.Assert(State == APIState.Offline);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
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)
|
||||
{
|
||||
Scheduler.Add(delegate { components.Add(component); });
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Users;
|
||||
|
||||
@ -42,6 +43,24 @@ namespace osu.Game.Online.API
|
||||
/// <param name="request">The request to perform.</param>
|
||||
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>
|
||||
/// Register a component to receive state changes.
|
||||
/// </summary>
|
||||
|
@ -9,6 +9,7 @@ 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
|
||||
{
|
||||
@ -37,10 +38,12 @@ namespace osu.Game.Online.API.Requests
|
||||
|
||||
private void onSuccess(APILegacyScores r)
|
||||
{
|
||||
Debug.Assert(ruleset.ID != null, "ruleset.ID != null");
|
||||
|
||||
foreach (APILegacyScoreInfo score in r.Scores)
|
||||
{
|
||||
score.Beatmap = beatmap;
|
||||
score.Ruleset = ruleset;
|
||||
score.OnlineRulesetID = ruleset.ID.Value;
|
||||
}
|
||||
|
||||
var userScore = r.UserScore;
|
||||
@ -48,7 +51,7 @@ namespace osu.Game.Online.API.Requests
|
||||
if (userScore != null)
|
||||
{
|
||||
userScore.Score.Beatmap = beatmap;
|
||||
userScore.Score.Ruleset = ruleset;
|
||||
userScore.Score.OnlineRulesetID = ruleset.ID.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,56 +5,106 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APILegacyScoreInfo : LegacyScoreInfo
|
||||
public class APILegacyScoreInfo
|
||||
{
|
||||
[JsonProperty(@"score")]
|
||||
private int totalScore
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
|
||||
{
|
||||
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")]
|
||||
private int maxCombo
|
||||
{
|
||||
set => MaxCombo = value;
|
||||
}
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
private User user
|
||||
{
|
||||
set => User = value;
|
||||
}
|
||||
public User User { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
private long onlineScoreID
|
||||
{
|
||||
set => OnlineScoreID = value;
|
||||
}
|
||||
public long OnlineScoreID { get; set; }
|
||||
|
||||
[JsonProperty(@"replay")]
|
||||
public bool Replay { get; set; }
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
private DateTimeOffset date
|
||||
{
|
||||
set => Date = value;
|
||||
}
|
||||
public DateTimeOffset Date { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmap")]
|
||||
private BeatmapInfo beatmap
|
||||
{
|
||||
set => Beatmap = value;
|
||||
}
|
||||
public BeatmapInfo Beatmap { get; set; }
|
||||
|
||||
[JsonProperty("accuracy")]
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
[JsonProperty(@"pp")]
|
||||
public double? PP { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmapset")]
|
||||
private BeatmapMetadata metadata
|
||||
public BeatmapMetadata Metadata
|
||||
{
|
||||
set
|
||||
{
|
||||
@ -67,68 +117,16 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
}
|
||||
|
||||
[JsonProperty(@"statistics")]
|
||||
private Dictionary<string, int> jsonStats
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public Dictionary<string, int> Statistics { get; set; }
|
||||
|
||||
[JsonProperty(@"mode_int")]
|
||||
public int OnlineRulesetID
|
||||
{
|
||||
get => RulesetID;
|
||||
set => RulesetID = value;
|
||||
}
|
||||
public int OnlineRulesetID { get; set; }
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
private string[] modStrings { get; set; }
|
||||
public string[] Mods { get; set; }
|
||||
|
||||
public override RulesetInfo Ruleset
|
||||
{
|
||||
get => base.Ruleset;
|
||||
set
|
||||
{
|
||||
base.Ruleset = value;
|
||||
|
||||
if (modStrings != null)
|
||||
{
|
||||
// Evaluate the mod string
|
||||
Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.Acronym)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
[JsonProperty("rank")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ScoreRank Rank { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -406,11 +406,11 @@ namespace osu.Game
|
||||
nextBeatmap?.LoadBeatmapAsync();
|
||||
}
|
||||
|
||||
private void currentTrackCompleted()
|
||||
private void currentTrackCompleted() => Schedule(() =>
|
||||
{
|
||||
if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled)
|
||||
musicController.NextTrack();
|
||||
}
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -41,6 +41,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private GetScoresRequest getScoresRequest;
|
||||
|
||||
protected APILegacyScores Scores
|
||||
@ -56,16 +59,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
return;
|
||||
}
|
||||
|
||||
scoreTable.Scores = value.Scores;
|
||||
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList();
|
||||
|
||||
scoreTable.Scores = scoreInfos;
|
||||
scoreTable.Show();
|
||||
|
||||
var topScore = value.Scores.First();
|
||||
var topScore = scoreInfos.First();
|
||||
var userScore = value.UserScore;
|
||||
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
|
||||
|
||||
topScoresContainer.Add(new DrawableTopScore(topScore));
|
||||
|
||||
if (userScore != null && userScore.Score.OnlineScoreID != topScore.OnlineScoreID)
|
||||
topScoresContainer.Add(new DrawableTopScore(userScore.Score, userScore.Position));
|
||||
if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID)
|
||||
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -43,18 +42,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
};
|
||||
req.Failure += _ => complete = true;
|
||||
|
||||
// This is done on a separate thread to support cancellation below
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
req.Perform(api);
|
||||
}
|
||||
catch
|
||||
{
|
||||
complete = true;
|
||||
}
|
||||
});
|
||||
api.PerformAsync(req);
|
||||
|
||||
while (!complete)
|
||||
{
|
||||
|
@ -191,15 +191,7 @@ namespace osu.Game.Overlays
|
||||
tcs.SetResult(false);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
req.Perform(API);
|
||||
}
|
||||
catch
|
||||
{
|
||||
initialFetchTask = null;
|
||||
tcs.SetResult(false);
|
||||
}
|
||||
await API.PerformAsync(req);
|
||||
|
||||
await tcs.Task;
|
||||
});
|
||||
|
@ -16,6 +16,7 @@ using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays.MedalSplash
|
||||
{
|
||||
[LongRunningLoad]
|
||||
public class DrawableMedal : Container, IStateful<DisplayState>
|
||||
{
|
||||
private const float scale_when_unlocked = 0.76f;
|
||||
|
@ -12,6 +12,7 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Header.Components
|
||||
{
|
||||
[LongRunningLoad]
|
||||
public class DrawableBadge : CompositeDrawable, IHasTooltip
|
||||
{
|
||||
public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40);
|
||||
|
@ -19,8 +19,8 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
private const int fade_duration = 200;
|
||||
|
||||
private Box underscoreLine;
|
||||
private readonly Box coloredBackground;
|
||||
private readonly Container background;
|
||||
private Box coloredBackground;
|
||||
private Container background;
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
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[]
|
||||
{
|
||||
background = new Container
|
||||
@ -53,21 +66,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
},
|
||||
Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
|
||||
},
|
||||
Content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = 0.97f,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colour)
|
||||
{
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
Content,
|
||||
underscoreLine = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
@ -101,7 +100,7 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
Origin = Anchor.CentreRight,
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
|
||||
}
|
||||
|
@ -29,14 +29,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
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() =>
|
||||
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
||||
|
||||
@ -45,10 +37,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
switch (type)
|
||||
{
|
||||
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:
|
||||
return new DrawableTotalScore(model);
|
||||
return new DrawableTotalScore(model.CreateScoreInfo(Rulesets));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,11 +66,14 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
};
|
||||
|
||||
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,
|
||||
Width = 60,
|
||||
FillMode = FillMode.Fit,
|
||||
};
|
||||
|
||||
default:
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics.Textures;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Recent
|
||||
{
|
||||
[LongRunningLoad]
|
||||
public class MedalIcon : Container
|
||||
{
|
||||
private readonly string slug;
|
||||
|
@ -273,14 +273,6 @@ namespace osu.Game.Rulesets.Objects
|
||||
return p0 + (p1 - p0) * (float)w;
|
||||
}
|
||||
|
||||
public bool Equals(SliderPath other)
|
||||
{
|
||||
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;
|
||||
}
|
||||
public bool Equals(SliderPath other) => ControlPoints.SequenceEqual(other.ControlPoints) && ExpectedDistance == other.ExpectedDistance && Type == other.Type;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ namespace osu.Game.Scoring.Legacy
|
||||
using (SerializationReader sr = new SerializationReader(stream))
|
||||
{
|
||||
currentRuleset = GetRuleset(sr.ReadByte());
|
||||
var scoreInfo = new LegacyScoreInfo { Ruleset = currentRuleset.RulesetInfo };
|
||||
var scoreInfo = new ScoreInfo { Ruleset = currentRuleset.RulesetInfo };
|
||||
|
||||
score.ScoreInfo = scoreInfo;
|
||||
|
||||
@ -53,12 +53,12 @@ namespace osu.Game.Scoring.Legacy
|
||||
// MD5Hash
|
||||
sr.ReadString();
|
||||
|
||||
scoreInfo.Count300 = sr.ReadUInt16();
|
||||
scoreInfo.Count100 = sr.ReadUInt16();
|
||||
scoreInfo.Count50 = sr.ReadUInt16();
|
||||
scoreInfo.CountGeki = sr.ReadUInt16();
|
||||
scoreInfo.CountKatu = sr.ReadUInt16();
|
||||
scoreInfo.CountMiss = sr.ReadUInt16();
|
||||
scoreInfo.SetCount300(sr.ReadUInt16());
|
||||
scoreInfo.SetCount100(sr.ReadUInt16());
|
||||
scoreInfo.SetCount50(sr.ReadUInt16());
|
||||
scoreInfo.SetCountGeki(sr.ReadUInt16());
|
||||
scoreInfo.SetCountKatu(sr.ReadUInt16());
|
||||
scoreInfo.SetCountMiss(sr.ReadUInt16());
|
||||
|
||||
scoreInfo.TotalScore = sr.ReadInt32();
|
||||
scoreInfo.MaxCombo = sr.ReadUInt16();
|
||||
|
143
osu.Game/Scoring/Legacy/ScoreInfoExtensions.cs
Normal file
143
osu.Game/Scoring/Legacy/ScoreInfoExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
@ -183,10 +183,21 @@ namespace osu.Game.Scoring
|
||||
|
||||
public override string ToString() => $"{User} playing {Beatmap}";
|
||||
|
||||
public bool Equals(ScoreInfo other) =>
|
||||
other != null
|
||||
&& other.OnlineScoreID == OnlineScoreID
|
||||
&& other.BeatmapInfoID == BeatmapInfoID
|
||||
&& other.Hash == Hash;
|
||||
public bool Equals(ScoreInfo other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
@ -24,7 +23,7 @@ namespace osu.Game.Screens.Ranking.Pages
|
||||
if (State.Value == DownloadState.LocallyAvailable)
|
||||
return ReplayAvailability.Local;
|
||||
|
||||
if (Model.Value is APILegacyScoreInfo apiScore && apiScore.Replay)
|
||||
if (!string.IsNullOrEmpty(Model.Value.Hash))
|
||||
return ReplayAvailability.Online;
|
||||
|
||||
return ReplayAvailability.NotAvailable;
|
||||
|
@ -70,7 +70,10 @@ namespace osu.Game.Screens.Ranking.Pages
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new UserHeader(Score.User)
|
||||
new DelayedLoadWrapper(new UserHeader(Score.User)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
})
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
@ -370,6 +373,7 @@ namespace osu.Game.Screens.Ranking.Pages
|
||||
}
|
||||
}
|
||||
|
||||
[LongRunningLoad]
|
||||
private class UserHeader : Container
|
||||
{
|
||||
private readonly User user;
|
||||
|
@ -79,8 +79,8 @@ namespace osu.Game.Screens.Select
|
||||
public bool IsUpperInclusive;
|
||||
|
||||
public bool Equals(OptionalRange<T> other)
|
||||
=> Min.Equals(other.Min)
|
||||
&& Max.Equals(other.Max)
|
||||
=> EqualityComparer<T?>.Default.Equals(Min, other.Min)
|
||||
&& EqualityComparer<T?>.Default.Equals(Max, other.Max)
|
||||
&& IsLowerInclusive.Equals(other.IsLowerInclusive)
|
||||
&& IsUpperInclusive.Equals(other.IsUpperInclusive);
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
{
|
||||
public Action<ScoreInfo> ScoreSelected;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private BeatmapInfo beatmap;
|
||||
|
||||
public BeatmapInfo Beatmap
|
||||
@ -172,7 +175,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
req.Success += r =>
|
||||
{
|
||||
scoresCallback?.Invoke(r.Scores);
|
||||
scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets)));
|
||||
TopScore = r.UserScore;
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -10,6 +11,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osuTK;
|
||||
|
||||
@ -27,6 +29,9 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
|
||||
protected override bool StartHidden => true;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
public UserTopScoreContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
@ -77,9 +82,11 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
if (newScore == null)
|
||||
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 =>
|
||||
{
|
||||
scoreContainer.Child = drawableScore;
|
||||
|
@ -240,6 +240,6 @@ namespace osu.Game.Tests.Beatmaps
|
||||
set => Objects = value;
|
||||
}
|
||||
|
||||
public virtual bool Equals(ConvertMapping<TConvertValue> other) => StartTime.Equals(other?.StartTime);
|
||||
public virtual bool Equals(ConvertMapping<TConvertValue> other) => StartTime == other?.StartTime;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user