1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:07:44 +08:00

Merge pull request #28659 from bdach/daily-challenge/integration

Use room watching functionality to receive realtime daily challenge updates
This commit is contained in:
Dean Herbert 2024-07-04 23:55:46 +09:00 committed by GitHub
commit aa72c09c3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 183 additions and 35 deletions

View File

@ -11,10 +11,11 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Screens.OnlinePlay.DailyChallenge; using osu.Game.Screens.OnlinePlay.DailyChallenge;
using osu.Game.Tests.Resources; using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
namespace osu.Game.Tests.Visual.DailyChallenge namespace osu.Game.Tests.Visual.DailyChallenge
{ {
@ -129,19 +130,27 @@ namespace osu.Game.Tests.Visual.DailyChallenge
}); });
AddStep("add normal score", () => AddStep("add normal score", () =>
{ {
var testScore = TestResources.CreateTestScoreInfo(); var ev = new NewScoreEvent(1, new APIUser
testScore.TotalScore = RNG.Next(1_000_000); {
Id = 2,
Username = "peppy",
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}, RNG.Next(1_000_000), null);
feed.AddNewScore(new DailyChallengeEventFeed.NewScoreEvent(testScore, null)); feed.AddNewScore(ev);
breakdown.AddNewScore(testScore); breakdown.AddNewScore(ev);
}); });
AddStep("add new user best", () => AddStep("add new user best", () =>
{ {
var testScore = TestResources.CreateTestScoreInfo(); var ev = new NewScoreEvent(1, new APIUser
testScore.TotalScore = RNG.Next(1_000_000); {
Id = 2,
Username = "peppy",
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}, RNG.Next(1_000_000), RNG.Next(1, 1000));
feed.AddNewScore(new DailyChallengeEventFeed.NewScoreEvent(testScore, RNG.Next(1, 1000))); feed.AddNewScore(ev);
breakdown.AddNewScore(testScore); breakdown.AddNewScore(ev);
}); });
} }

View File

@ -7,8 +7,10 @@ using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Screens.OnlinePlay.DailyChallenge; using osu.Game.Screens.OnlinePlay.DailyChallenge;
using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
using osu.Game.Tests.Resources; using osu.Game.Tests.Resources;
namespace osu.Game.Tests.Visual.DailyChallenge namespace osu.Game.Tests.Visual.DailyChallenge
@ -50,26 +52,41 @@ namespace osu.Game.Tests.Visual.DailyChallenge
AddStep("add normal score", () => AddStep("add normal score", () =>
{ {
var testScore = TestResources.CreateTestScoreInfo(); var ev = new NewScoreEvent(1, new APIUser
testScore.TotalScore = RNG.Next(1_000_000); {
Id = 2,
Username = "peppy",
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}, RNG.Next(1_000_000), null);
feed.AddNewScore(new DailyChallengeEventFeed.NewScoreEvent(testScore, null)); feed.AddNewScore(ev);
}); });
AddStep("add new user best", () => AddStep("add new user best", () =>
{ {
var ev = new NewScoreEvent(1, new APIUser
{
Id = 2,
Username = "peppy",
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}, RNG.Next(1_000_000), RNG.Next(11, 1000));
var testScore = TestResources.CreateTestScoreInfo(); var testScore = TestResources.CreateTestScoreInfo();
testScore.TotalScore = RNG.Next(1_000_000); testScore.TotalScore = RNG.Next(1_000_000);
feed.AddNewScore(new DailyChallengeEventFeed.NewScoreEvent(testScore, RNG.Next(1, 1000))); feed.AddNewScore(ev);
}); });
AddStep("add top 10 score", () => AddStep("add top 10 score", () =>
{ {
var testScore = TestResources.CreateTestScoreInfo(); var ev = new NewScoreEvent(1, new APIUser
testScore.TotalScore = RNG.Next(1_000_000); {
Id = 2,
Username = "peppy",
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}, RNG.Next(1_000_000), RNG.Next(1, 10));
feed.AddNewScore(new DailyChallengeEventFeed.NewScoreEvent(testScore, RNG.Next(1, 10))); feed.AddNewScore(ev);
}); });
} }
} }

View File

@ -7,9 +7,10 @@ using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Screens.OnlinePlay.DailyChallenge; using osu.Game.Screens.OnlinePlay.DailyChallenge;
using osu.Game.Tests.Resources; using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
namespace osu.Game.Tests.Visual.DailyChallenge namespace osu.Game.Tests.Visual.DailyChallenge
{ {
@ -51,10 +52,14 @@ namespace osu.Game.Tests.Visual.DailyChallenge
AddStep("set initial data", () => breakdown.SetInitialCounts([1, 4, 9, 16, 25, 36, 49, 36, 25, 16, 9, 4, 1])); AddStep("set initial data", () => breakdown.SetInitialCounts([1, 4, 9, 16, 25, 36, 49, 36, 25, 16, 9, 4, 1]));
AddStep("add new score", () => AddStep("add new score", () =>
{ {
var testScore = TestResources.CreateTestScoreInfo(); var ev = new NewScoreEvent(1, new APIUser
testScore.TotalScore = RNG.Next(1_000_000); {
Id = 2,
Username = "peppy",
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
}, RNG.Next(1_000_000), null);
breakdown.AddNewScore(testScore); breakdown.AddNewScore(ev);
}); });
} }
} }

View File

@ -256,7 +256,7 @@ namespace osu.Game.Online.Metadata
throw new OperationCanceledException(); throw new OperationCanceledException();
Debug.Assert(connection != null); Debug.Assert(connection != null);
await connection.InvokeAsync(nameof(IMetadataServer.EndWatchingMultiplayerRoom)).ConfigureAwait(false); await connection.InvokeAsync(nameof(IMetadataServer.EndWatchingMultiplayerRoom), id).ConfigureAwait(false);
} }
public override async Task DisconnectRequested() public override async Task DisconnectRequested()

View File

@ -8,21 +8,29 @@ using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation; using osu.Game.Localisation;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Metadata;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.OnlinePlay.Playlists;
@ -47,6 +55,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
private Sample? sampleStart; private Sample? sampleStart;
private IDisposable? userModsSelectOverlayRegistration; private IDisposable? userModsSelectOverlayRegistration;
private DailyChallengeScoreBreakdown breakdown = null!;
private DailyChallengeEventFeed feed = null!;
[Cached] [Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
@ -68,6 +79,12 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
[Resolved] [Resolved]
private IOverlayManager? overlayManager { get; set; } private IOverlayManager? overlayManager { get; set; }
[Resolved]
private MetadataClient metadataClient { get; set; } = null!;
[Resolved]
private UserLookupCache userLookupCache { get; set; } = null!;
public override bool DisallowExternalBeatmapRulesetChanges => true; public override bool DisallowExternalBeatmapRulesetChanges => true;
public DailyChallenge(Room room) public DailyChallenge(Room room)
@ -162,9 +179,39 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
{ {
new Drawable?[] new Drawable?[]
{ {
new DailyChallengeTimeRemainingRing new GridContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RowDimensions =
[
new Dimension(),
new Dimension()
],
Content = new[]
{
new Drawable[]
{
new DailyChallengeCarousel
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
new DailyChallengeTimeRemainingRing(),
breakdown = new DailyChallengeScoreBreakdown(),
}
}
},
[
feed = new DailyChallengeEventFeed
{
RelativeSizeAxes = Axes.Both,
}
],
},
}, },
null, null,
// Middle column (leaderboard) // Middle column (leaderboard)
@ -275,6 +322,33 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
var allowedMods = playlistItem.AllowedMods.Select(m => m.ToMod(rulesetInstance)); var allowedMods = playlistItem.AllowedMods.Select(m => m.ToMod(rulesetInstance));
userModsSelectOverlay.IsValidMod = m => allowedMods.Any(a => a.GetType() == m.GetType()); userModsSelectOverlay.IsValidMod = m => allowedMods.Any(a => a.GetType() == m.GetType());
} }
metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet;
}
private void onRoomScoreSet(MultiplayerRoomScoreSetEvent e)
{
if (e.RoomID != room.RoomID.Value || e.PlaylistItemID != playlistItem.ID)
return;
userLookupCache.GetUserAsync(e.UserID).ContinueWith(t =>
{
if (t.Exception != null)
{
Logger.Log($@"Could not display room score set event: {t.Exception}", LoggingTarget.Network);
return;
}
APIUser? user = t.GetResultSafely();
if (user == null) return;
var ev = new NewScoreEvent(e.ScoreID, user, e.TotalScore, e.NewRank);
Schedule(() =>
{
breakdown.AddNewScore(ev);
feed.AddNewScore(ev);
});
});
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -294,6 +368,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
var beatmap = beatmapManager.QueryBeatmap(b => b.OnlineID == playlistItem.Beatmap.OnlineID); var beatmap = beatmapManager.QueryBeatmap(b => b.OnlineID == playlistItem.Beatmap.OnlineID);
Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmap); // this will gracefully fall back to dummy beatmap if missing locally. Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmap); // this will gracefully fall back to dummy beatmap if missing locally.
Ruleset.Value = rulesets.GetRuleset(playlistItem.RulesetID); Ruleset.Value = rulesets.GetRuleset(playlistItem.RulesetID);
applyLoopingToTrack();
} }
public override void OnEntering(ScreenTransitionEvent e) public override void OnEntering(ScreenTransitionEvent e)
@ -303,6 +378,25 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
waves.Show(); waves.Show();
roomManager.JoinRoom(room); roomManager.JoinRoom(room);
applyLoopingToTrack(); applyLoopingToTrack();
metadataClient.BeginWatchingMultiplayerRoom(room.RoomID.Value!.Value).ContinueWith(t =>
{
if (t.Exception != null)
{
Logger.Error(t.Exception, @"Failed to subscribe to room updates", LoggingTarget.Network);
return;
}
MultiplayerPlaylistItemStats[] stats = t.GetResultSafely();
var itemStats = stats.SingleOrDefault(item => item.PlaylistItemID == playlistItem.ID);
if (itemStats == null) return;
Schedule(() => breakdown.SetInitialCounts(itemStats.TotalScoreDistribution));
});
beatmapAvailabilityTracker.SelectedItem.Value = playlistItem;
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => trySetDailyChallengeBeatmap(), true);
userModsSelectOverlay.SelectedItem.Value = playlistItem;
} }
public override void OnResuming(ScreenTransitionEvent e) public override void OnResuming(ScreenTransitionEvent e)
@ -327,6 +421,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut(); this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
roomManager.PartRoom(); roomManager.PartRoom();
metadataClient.EndWatchingMultiplayerRoom(room.RoomID.Value!.Value).FireAndForget();
return base.OnExiting(e); return base.OnExiting(e);
} }
@ -375,6 +470,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
base.Dispose(isDisposing); base.Dispose(isDisposing);
userModsSelectOverlayRegistration?.Dispose(); userModsSelectOverlayRegistration?.Dispose();
if (metadataClient.IsNotNull())
metadataClient.MultiplayerRoomScoreSet -= onRoomScoreSet;
} }
} }
} }

View File

@ -9,8 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.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.API.Requests.Responses; using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
using osu.Game.Scoring;
using osu.Game.Users.Drawables; using osu.Game.Users.Drawables;
using osuTK; using osuTK;
@ -70,8 +69,6 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
} }
} }
public record NewScoreEvent(IScoreInfo Score, int? NewRank);
private partial class DailyChallengeEventFeedFlow : FillFlowContainer private partial class DailyChallengeEventFeedFlow : FillFlowContainer
{ {
public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse(); public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Reverse();
@ -98,8 +95,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
// TODO: cast is temporary, will be removed later new ClickableAvatar(newScore.User)
new ClickableAvatar((APIUser)newScore.Score.User)
{ {
Size = new Vector2(16), Size = new Vector2(16),
Masking = true, Masking = true,
@ -117,9 +113,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
} }
}; };
text.AddUserLink(newScore.Score.User); text.AddUserLink(newScore.User);
text.AddText(" got "); text.AddText(" got ");
text.AddLink($"{newScore.Score.TotalScore:N0} points", () => { }); // TODO: present the score here text.AddLink($"{newScore.TotalScore:N0} points", () => { }); // TODO: present the score here
if (newScore.NewRank != null) if (newScore.NewRank != null)
text.AddText($" and achieved rank #{newScore.NewRank.Value:N0}"); text.AddText($" and achieved rank #{newScore.NewRank.Value:N0}");

View File

@ -13,7 +13,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Metadata; using osu.Game.Online.Metadata;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
using osuTK; using osuTK;
namespace osu.Game.Screens.OnlinePlay.DailyChallenge namespace osu.Game.Screens.OnlinePlay.DailyChallenge
@ -67,15 +67,15 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
} }
} }
public void AddNewScore(IScoreInfo scoreInfo) public void AddNewScore(NewScoreEvent newScoreEvent)
{ {
int targetBin = (int)Math.Clamp(Math.Floor((float)scoreInfo.TotalScore / 100000), 0, bin_count - 1); int targetBin = (int)Math.Clamp(Math.Floor((float)newScoreEvent.TotalScore / 100000), 0, bin_count - 1);
bins[targetBin] += 1; bins[targetBin] += 1;
updateCounts(); updateCounts();
var text = new OsuSpriteText var text = new OsuSpriteText
{ {
Text = scoreInfo.TotalScore.ToString(@"N0"), Text = newScoreEvent.TotalScore.ToString(@"N0"),
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
Font = OsuFont.Default.With(size: 30), Font = OsuFont.Default.With(size: 30),
@ -108,7 +108,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
private void updateCounts() private void updateCounts()
{ {
long max = bins.Max(); long max = Math.Max(bins.Max(), 1);
for (int i = 0; i < bin_count; ++i) for (int i = 0; i < bin_count; ++i)
barsContainer[i].UpdateCounts(bins[i], max); barsContainer[i].UpdateCounts(bins[i], max);
} }

View File

@ -0,0 +1,23 @@
// 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.Online.API.Requests.Responses;
namespace osu.Game.Screens.OnlinePlay.DailyChallenge.Events
{
public class NewScoreEvent
{
public NewScoreEvent(long scoreID, APIUser user, long totalScore, int? newRank)
{
ScoreID = scoreID;
User = user;
TotalScore = totalScore;
NewRank = newRank;
}
public long ScoreID { get; }
public APIUser User { get; }
public long TotalScore { get; }
public int? NewRank { get; }
}
}