mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 09:17:51 +08:00
Merge pull request #18623 from LittleEndu/new-me-recommender
Use new own profile statistics in difficulty recommender
This commit is contained in:
commit
8879c59b36
@ -5,12 +5,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
@ -23,38 +22,28 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
public class TestSceneBeatmapRecommendations : OsuGameTestScene
|
||||
{
|
||||
[Resolved]
|
||||
private IRulesetStore rulesetStore { get; set; }
|
||||
|
||||
[SetUpSteps]
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
AddStep("register request handling", () =>
|
||||
{
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case GetUserRequest userRequest:
|
||||
userRequest.TriggerSuccess(getUser(userRequest.Ruleset.OnlineID));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
});
|
||||
|
||||
base.SetUpSteps();
|
||||
|
||||
APIUser getUser(int? rulesetID)
|
||||
AddStep("populate ruleset statistics", () =>
|
||||
{
|
||||
return new APIUser
|
||||
Dictionary<string, UserStatistics> rulesetStatistics = new Dictionary<string, UserStatistics>();
|
||||
|
||||
rulesetStore.AvailableRulesets.Where(ruleset => ruleset.IsLegacyRuleset()).ForEach(rulesetInfo =>
|
||||
{
|
||||
Username = @"Dummy",
|
||||
Id = 1001,
|
||||
Statistics = new UserStatistics
|
||||
rulesetStatistics[rulesetInfo.ShortName] = new UserStatistics
|
||||
{
|
||||
PP = getNecessaryPP(rulesetID)
|
||||
}
|
||||
};
|
||||
}
|
||||
PP = getNecessaryPP(rulesetInfo.OnlineID)
|
||||
};
|
||||
});
|
||||
|
||||
API.LocalUser.Value.RulesetsStatistics = rulesetStatistics;
|
||||
});
|
||||
|
||||
decimal getNecessaryPP(int? rulesetID)
|
||||
{
|
||||
|
@ -7,11 +7,8 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
@ -25,26 +22,15 @@ namespace osu.Game.Beatmaps
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IRulesetStore rulesets { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private Bindable<RulesetInfo> ruleset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user for which the last requests were run.
|
||||
/// </summary>
|
||||
private int? requestedUserId;
|
||||
|
||||
private readonly Dictionary<IRulesetInfo, double> recommendedDifficultyMapping = new Dictionary<IRulesetInfo, double>();
|
||||
|
||||
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
||||
private readonly Dictionary<string, double> recommendedDifficultyMapping = new Dictionary<string, double>();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
apiState.BindTo(api.State);
|
||||
apiState.BindValueChanged(onlineStateChanged, true);
|
||||
api.LocalUser.BindValueChanged(_ => populateValues(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -58,12 +44,12 @@ namespace osu.Game.Beatmaps
|
||||
[CanBeNull]
|
||||
public BeatmapInfo GetRecommendedBeatmap(IEnumerable<BeatmapInfo> beatmaps)
|
||||
{
|
||||
foreach (var r in orderedRulesets)
|
||||
foreach (string r in orderedRulesets)
|
||||
{
|
||||
if (!recommendedDifficultyMapping.TryGetValue(r, out double recommendation))
|
||||
continue;
|
||||
|
||||
BeatmapInfo beatmapInfo = beatmaps.Where(b => b.Ruleset.Equals(r)).OrderBy(b =>
|
||||
BeatmapInfo beatmapInfo = beatmaps.Where(b => b.Ruleset.ShortName.Equals(r)).OrderBy(b =>
|
||||
{
|
||||
double difference = b.StarRating - recommendation;
|
||||
return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder
|
||||
@ -76,55 +62,35 @@ namespace osu.Game.Beatmaps
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fetchRecommendedValues()
|
||||
private void populateValues()
|
||||
{
|
||||
if (recommendedDifficultyMapping.Count > 0 && api.LocalUser.Value.Id == requestedUserId)
|
||||
if (api.LocalUser.Value.RulesetsStatistics == null)
|
||||
return;
|
||||
|
||||
requestedUserId = api.LocalUser.Value.Id;
|
||||
|
||||
// only query API for built-in rulesets
|
||||
rulesets.AvailableRulesets.Where(ruleset => ruleset.IsLegacyRuleset()).ForEach(rulesetInfo =>
|
||||
foreach (var kvp in api.LocalUser.Value.RulesetsStatistics)
|
||||
{
|
||||
var req = new GetUserRequest(api.LocalUser.Value.Id, rulesetInfo);
|
||||
|
||||
req.Success += result =>
|
||||
{
|
||||
// algorithm taken from https://github.com/ppy/osu-web/blob/e6e2825516449e3d0f3f5e1852c6bdd3428c3437/app/Models/User.php#L1505
|
||||
recommendedDifficultyMapping[rulesetInfo] = Math.Pow((double)(result.Statistics.PP ?? 0), 0.4) * 0.195;
|
||||
};
|
||||
|
||||
api.Queue(req);
|
||||
});
|
||||
// algorithm taken from https://github.com/ppy/osu-web/blob/e6e2825516449e3d0f3f5e1852c6bdd3428c3437/app/Models/User.php#L1505
|
||||
recommendedDifficultyMapping[kvp.Key] = Math.Pow((double)(kvp.Value.PP ?? 0), 0.4) * 0.195;
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns>
|
||||
/// Rulesets ordered descending by their respective recommended difficulties.
|
||||
/// The currently selected ruleset will always be first.
|
||||
/// </returns>
|
||||
private IEnumerable<IRulesetInfo> orderedRulesets
|
||||
private IEnumerable<string> orderedRulesets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LoadState < LoadState.Ready || ruleset.Value == null)
|
||||
return Enumerable.Empty<RulesetInfo>();
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
return recommendedDifficultyMapping
|
||||
.OrderByDescending(pair => pair.Value)
|
||||
.Select(pair => pair.Key)
|
||||
.Where(r => !r.Equals(ruleset.Value))
|
||||
.Prepend(ruleset.Value);
|
||||
.Where(r => !r.Equals(ruleset.Value.ShortName))
|
||||
.Prepend(ruleset.Value.ShortName);
|
||||
}
|
||||
}
|
||||
|
||||
private void onlineStateChanged(ValueChangedEvent<APIState> state) => Schedule(() =>
|
||||
{
|
||||
switch (state.NewValue)
|
||||
{
|
||||
case APIState.Online:
|
||||
fetchRecommendedValues();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user