mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 09:42:54 +08:00
Introduce LocalUserStatisticsProvider
component
This commit is contained in:
parent
b0420f7ed9
commit
91fb59ee15
@ -0,0 +1,141 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Online;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public partial class TestSceneLocalUserStatisticsProvider : OsuTestScene
|
||||||
|
{
|
||||||
|
private LocalUserStatisticsProvider statisticsProvider = null!;
|
||||||
|
|
||||||
|
private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>();
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("clear statistics", () => serverSideStatistics.Clear());
|
||||||
|
|
||||||
|
setUser(1000);
|
||||||
|
|
||||||
|
AddStep("setup provider", () =>
|
||||||
|
{
|
||||||
|
OsuSpriteText text;
|
||||||
|
|
||||||
|
((DummyAPIAccess)API).HandleRequest = r =>
|
||||||
|
{
|
||||||
|
switch (r)
|
||||||
|
{
|
||||||
|
case GetUserRequest userRequest:
|
||||||
|
int userId = int.Parse(userRequest.Lookup);
|
||||||
|
string rulesetName = userRequest.Ruleset!.ShortName;
|
||||||
|
var response = new APIUser
|
||||||
|
{
|
||||||
|
Id = userId,
|
||||||
|
Statistics = tryGetStatistics(userId, rulesetName)
|
||||||
|
};
|
||||||
|
|
||||||
|
userRequest.TriggerSuccess(response);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
Add(statisticsProvider = new LocalUserStatisticsProvider());
|
||||||
|
Add(text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
});
|
||||||
|
|
||||||
|
statisticsProvider.Statistics.BindValueChanged(s =>
|
||||||
|
{
|
||||||
|
text.Text = s.NewValue == null
|
||||||
|
? "Statistics: (null)"
|
||||||
|
: $"Statistics: (total score: {s.NewValue.TotalScore:N0})";
|
||||||
|
});
|
||||||
|
|
||||||
|
Ruleset.Value = new OsuRuleset().RulesetInfo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInitialStatistics()
|
||||||
|
{
|
||||||
|
AddAssert("initial statistics populated", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(4_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRulesetChanges()
|
||||||
|
{
|
||||||
|
AddAssert("statistics from osu", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(4_000_000));
|
||||||
|
AddStep("change ruleset to taiko", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
|
||||||
|
AddAssert("statistics from taiko", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(3_000_000));
|
||||||
|
AddStep("change ruleset to catch", () => Ruleset.Value = new CatchRuleset().RulesetInfo);
|
||||||
|
AddAssert("statistics from catch", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(2_000_000));
|
||||||
|
AddStep("change ruleset to mania", () => Ruleset.Value = new ManiaRuleset().RulesetInfo);
|
||||||
|
AddAssert("statistics from mania", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(1_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUserChanges()
|
||||||
|
{
|
||||||
|
setUser(1001);
|
||||||
|
|
||||||
|
AddStep("update statistics for user 1000", () =>
|
||||||
|
{
|
||||||
|
serverSideStatistics[(1000, "osu")] = new UserStatistics { TotalScore = 5_000_000 };
|
||||||
|
serverSideStatistics[(1000, "taiko")] = new UserStatistics { TotalScore = 6_000_000 };
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("statistics matches user 1001 from osu", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(4_000_000));
|
||||||
|
|
||||||
|
AddStep("change ruleset to taiko", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
|
||||||
|
AddAssert("statistics matches user 1001 from taiko", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(3_000_000));
|
||||||
|
|
||||||
|
AddStep("change ruleset to osu", () => Ruleset.Value = new OsuRuleset().RulesetInfo);
|
||||||
|
setUser(1000, false);
|
||||||
|
|
||||||
|
AddAssert("statistics matches user 1000 from osu", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(5_000_000));
|
||||||
|
|
||||||
|
AddStep("change ruleset to osu", () => Ruleset.Value = new TaikoRuleset().RulesetInfo);
|
||||||
|
AddAssert("statistics matches user 1000 from taiko", () => statisticsProvider.Statistics.Value.AsNonNull().TotalScore, () => Is.EqualTo(6_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserStatistics tryGetStatistics(int userId, string rulesetName)
|
||||||
|
=> serverSideStatistics.TryGetValue((userId, rulesetName), out var stats) ? stats : new UserStatistics();
|
||||||
|
|
||||||
|
private void setUser(int userId, bool generateStatistics = true)
|
||||||
|
{
|
||||||
|
AddStep($"set local user to {userId}", () =>
|
||||||
|
{
|
||||||
|
if (generateStatistics)
|
||||||
|
{
|
||||||
|
serverSideStatistics[(userId, "osu")] = new UserStatistics { TotalScore = 4_000_000 };
|
||||||
|
serverSideStatistics[(userId, "taiko")] = new UserStatistics { TotalScore = 3_000_000 };
|
||||||
|
serverSideStatistics[(userId, "fruits")] = new UserStatistics { TotalScore = 2_000_000 };
|
||||||
|
serverSideStatistics[(userId, "mania")] = new UserStatistics { TotalScore = 1_000_000 };
|
||||||
|
}
|
||||||
|
|
||||||
|
((DummyAPIAccess)API).LocalUser.Value = new APIUser { Id = userId };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
osu.Game/Online/LocalUserStatisticsProvider.cs
Normal file
94
osu.Game/Online/LocalUserStatisticsProvider.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Extensions;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
|
namespace osu.Game.Online
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A component that is responsible for providing the latest statistics of the logged-in user for the game-wide selected ruleset.
|
||||||
|
/// </summary>
|
||||||
|
public partial class LocalUserStatisticsProvider : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The statistics of the logged-in user for the game-wide selected ruleset.
|
||||||
|
/// </summary>
|
||||||
|
public IBindable<UserStatistics?> Statistics => statistics;
|
||||||
|
|
||||||
|
private readonly Bindable<UserStatistics?> statistics = new Bindable<UserStatistics?>();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, UserStatistics> allStatistics = new Dictionary<string, UserStatistics>();
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
statistics.BindValueChanged(v =>
|
||||||
|
{
|
||||||
|
if (api.LocalUser.Value != null && v.NewValue != null)
|
||||||
|
api.LocalUser.Value.Statistics = v.NewValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
ruleset.BindValueChanged(_ => updateStatisticsBindable());
|
||||||
|
|
||||||
|
api.LocalUser.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
allStatistics.Clear();
|
||||||
|
updateStatisticsBindable();
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetUserRequest? currentRequest;
|
||||||
|
|
||||||
|
private void updateStatisticsBindable() => Schedule(() =>
|
||||||
|
{
|
||||||
|
statistics.Value = null;
|
||||||
|
|
||||||
|
if (api.LocalUser.Value == null || api.LocalUser.Value.OnlineID <= 1 || !ruleset.Value.IsLegacyRuleset())
|
||||||
|
{
|
||||||
|
statistics.Value = new UserStatistics();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentRequest?.CompletionState == APIRequestCompletionState.Waiting)
|
||||||
|
{
|
||||||
|
currentRequest.Cancel();
|
||||||
|
currentRequest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allStatistics.TryGetValue(ruleset.Value.ShortName, out var existing))
|
||||||
|
statistics.Value = existing;
|
||||||
|
else
|
||||||
|
requestStatistics(ruleset.Value);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void requestStatistics(RulesetInfo ruleset)
|
||||||
|
{
|
||||||
|
currentRequest = new GetUserRequest(api.LocalUser.Value.OnlineID, ruleset);
|
||||||
|
currentRequest.Success += u => statistics.Value = allStatistics[ruleset.ShortName] = u.Statistics;
|
||||||
|
api.Queue(currentRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateStatistics(UserStatistics statistics, RulesetInfo statisticsRuleset)
|
||||||
|
{
|
||||||
|
allStatistics[statisticsRuleset.ShortName] = statistics;
|
||||||
|
|
||||||
|
if (statisticsRuleset.ShortName == ruleset.Value.ShortName)
|
||||||
|
updateStatisticsBindable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -208,6 +208,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
private MetadataClient metadataClient;
|
private MetadataClient metadataClient;
|
||||||
private SoloStatisticsWatcher soloStatisticsWatcher;
|
private SoloStatisticsWatcher soloStatisticsWatcher;
|
||||||
|
private LocalUserStatisticsProvider localUserStatisticsProvider;
|
||||||
|
|
||||||
private RealmAccess realm;
|
private RealmAccess realm;
|
||||||
|
|
||||||
@ -328,7 +329,9 @@ namespace osu.Game
|
|||||||
dependencies.CacheAs(SpectatorClient = new OnlineSpectatorClient(endpoints));
|
dependencies.CacheAs(SpectatorClient = new OnlineSpectatorClient(endpoints));
|
||||||
dependencies.CacheAs(MultiplayerClient = new OnlineMultiplayerClient(endpoints));
|
dependencies.CacheAs(MultiplayerClient = new OnlineMultiplayerClient(endpoints));
|
||||||
dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints));
|
dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints));
|
||||||
dependencies.CacheAs(soloStatisticsWatcher = new SoloStatisticsWatcher());
|
|
||||||
|
dependencies.CacheAs(localUserStatisticsProvider = new LocalUserStatisticsProvider());
|
||||||
|
dependencies.CacheAs(soloStatisticsWatcher = new SoloStatisticsWatcher(localUserStatisticsProvider));
|
||||||
|
|
||||||
base.Content.Add(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient));
|
base.Content.Add(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient));
|
||||||
|
|
||||||
@ -371,6 +374,7 @@ namespace osu.Game
|
|||||||
base.Content.Add(SpectatorClient);
|
base.Content.Add(SpectatorClient);
|
||||||
base.Content.Add(MultiplayerClient);
|
base.Content.Add(MultiplayerClient);
|
||||||
base.Content.Add(metadataClient);
|
base.Content.Add(metadataClient);
|
||||||
|
base.Content.Add(localUserStatisticsProvider);
|
||||||
base.Content.Add(soloStatisticsWatcher);
|
base.Content.Add(soloStatisticsWatcher);
|
||||||
|
|
||||||
base.Content.Add(rulesetConfigCache);
|
base.Content.Add(rulesetConfigCache);
|
||||||
|
Loading…
Reference in New Issue
Block a user