1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 10:18:22 +08:00

Merge pull request #29542 from frenzibyte/show-daily-challenge-intro-once-per-session

Show daily challenge intro screen once per session
This commit is contained in:
Dean Herbert 2024-09-01 21:27:16 +09:00 committed by GitHub
commit e79604cc13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 149 additions and 56 deletions

View File

@ -2,19 +2,21 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Online.API;
using osu.Game.Online.Metadata;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Tests.Resources;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.DailyChallenge;
using osu.Game.Tests.Visual.Metadata;
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK.Graphics;
using osuTK.Input;
using CreateRoomRequest = osu.Game.Online.Rooms.CreateRoomRequest;
namespace osu.Game.Tests.Visual.DailyChallenge
@ -27,63 +29,61 @@ namespace osu.Game.Tests.Visual.DailyChallenge
[Cached(typeof(INotificationOverlay))]
private NotificationOverlay notificationOverlay = new NotificationOverlay();
private Room room = null!;
[BackgroundDependencyLoader]
private void load()
{
base.Content.Add(notificationOverlay);
base.Content.Add(metadataClient);
Add(notificationOverlay);
Add(metadataClient);
// add button to observe for daily challenge changes and perform its logic.
Add(new DailyChallengeButton(@"button-default-select", new Color4(102, 68, 204, 255), _ => { }, 0, Key.D));
}
[Test]
[Solo]
public void TestDailyChallenge()
{
var room = new Room
{
RoomID = { Value = 1234 },
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
{
new PlaylistItem(CreateAPIBeatmapSet().Beatmaps.First())
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
Category = { Value = RoomCategory.DailyChallenge }
};
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
AddStep("push screen", () => LoadScreen(new Screens.OnlinePlay.DailyChallenge.DailyChallengeIntro(room)));
startChallenge(1234);
AddStep("push screen", () => LoadScreen(new DailyChallengeIntro(room)));
}
[Test]
public void TestNotifications()
public void TestPlayIntroOnceFlag()
{
var room = new Room
startChallenge(1234);
AddStep("set intro played flag", () => Dependencies.Get<SessionStatics>().SetValue(Static.DailyChallengeIntroPlayed, true));
startChallenge(1235);
AddAssert("intro played flag reset", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed), () => Is.False);
AddStep("push screen", () => LoadScreen(new DailyChallengeIntro(room)));
AddUntilStep("intro played flag set", () => Dependencies.Get<SessionStatics>().Get<bool>(Static.DailyChallengeIntroPlayed), () => Is.True);
}
private void startChallenge(int roomId)
{
AddStep("add room", () =>
{
RoomID = { Value = 1234 },
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
API.Perform(new CreateRoomRequest(room = new Room
{
new PlaylistItem(TestResources.CreateTestBeatmapSetInfo().Beatmaps.First())
RoomID = { Value = roomId },
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
EndDate = { Value = DateTimeOffset.Now.AddHours(12) },
Category = { Value = RoomCategory.DailyChallenge }
};
AddStep("add room", () => API.Perform(new CreateRoomRequest(room)));
AddStep("set daily challenge info", () => metadataClient.DailyChallengeInfo.Value = new DailyChallengeInfo { RoomID = 1234 });
Screens.OnlinePlay.DailyChallenge.DailyChallenge screen = null!;
AddStep("push screen", () => LoadScreen(screen = new Screens.OnlinePlay.DailyChallenge.DailyChallenge(room)));
AddUntilStep("wait for screen", () => screen.IsCurrentScreen());
AddStep("daily challenge ended", () => metadataClient.DailyChallengeInfo.Value = null);
new PlaylistItem(CreateAPIBeatmap(new OsuRuleset().RulesetInfo))
{
RequiredMods = [new APIMod(new OsuModTraceable())],
AllowedMods = [new APIMod(new OsuModDoubleTime())]
}
},
StartDate = { Value = DateTimeOffset.Now },
EndDate = { Value = DateTimeOffset.Now.AddHours(24) },
Category = { Value = RoomCategory.DailyChallenge }
}));
});
AddStep("signal client", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = roomId }));
}
}
}

View File

@ -103,15 +103,79 @@ namespace osu.Game.Tests.Visual.UserInterface
foreach (var notification in notificationOverlay.AllNotifications)
notification.Close(runFlingAnimation: false);
});
AddStep("beatmap of the day not active", () => metadataClient.DailyChallengeUpdated(null));
AddAssert("no notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.Zero);
AddStep("hide button's parent", () => buttonContainer.Hide());
AddStep("beatmap of the day active", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo
{
RoomID = 1234,
}));
AddAssert("no notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.Zero);
}
[Test]
public void TestDailyChallengeButtonOldChallenge()
{
AddStep("set up API", () => dummyAPI.HandleRequest = req =>
{
switch (req)
{
case GetRoomRequest getRoomRequest:
if (getRoomRequest.RoomId != 1234)
return false;
var beatmap = CreateAPIBeatmap();
beatmap.OnlineID = 1001;
getRoomRequest.TriggerSuccess(new Room
{
RoomID = { Value = 1234 },
Playlist =
{
new PlaylistItem(beatmap)
},
StartDate = { Value = DateTimeOffset.Now.AddMinutes(-50) },
EndDate = { Value = DateTimeOffset.Now.AddSeconds(30) }
});
return true;
default:
return false;
}
});
NotificationOverlay notificationOverlay = null!;
AddStep("beatmap of the day not active", () => metadataClient.DailyChallengeUpdated(null));
AddStep("add content", () =>
{
notificationOverlay = new NotificationOverlay();
Children = new Drawable[]
{
notificationOverlay,
new DependencyProvidingContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
CachedDependencies = [(typeof(INotificationOverlay), notificationOverlay)],
Child = new DailyChallengeButton(@"button-default-select", new Color4(102, 68, 204, 255), _ => { }, 0, Key.D)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
ButtonSystemState = ButtonSystemState.TopLevel,
},
},
};
});
AddStep("beatmap of the day active", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo
{
RoomID = 1234
}));
AddAssert("no notification posted", () => notificationOverlay.AllNotifications.Count(), () => Is.Zero);
}
}
}

View File

@ -80,5 +80,11 @@ namespace osu.Game.Configuration
/// Stores the local user's last score (can be completed or aborted).
/// </summary>
LastLocalUserScore,
/// <summary>
/// Whether the intro animation for the daily challenge screen has been played once.
/// This is reset when a new challenge is up.
/// </summary>
DailyChallengeIntroPlayed,
}
}

View File

@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading;
using osu.Framework.Utils;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Localisation;
@ -46,6 +47,9 @@ namespace osu.Game.Screens.Menu
[Resolved]
private INotificationOverlay? notificationOverlay { get; set; }
[Resolved]
private SessionStatics statics { get; set; } = null!;
public DailyChallengeButton(string sampleName, Color4 colour, Action<MainMenuButton>? clickAction = null, params Key[] triggerKeys)
: base(ButtonSystemStrings.DailyChallenge, sampleName, OsuIcon.DailyChallenge, colour, clickAction, triggerKeys)
{
@ -128,7 +132,7 @@ namespace osu.Game.Screens.Menu
}
}
private long? lastNotifiedDailyChallengeRoomId;
private long? lastDailyChallengeRoomID;
private void dailyChallengeChanged(ValueChangedEvent<DailyChallengeInfo?> _)
{
@ -151,13 +155,16 @@ namespace osu.Game.Screens.Menu
Room = room;
cover.OnlineInfo = TooltipContent = room.Playlist.FirstOrDefault()?.Beatmap.BeatmapSet as APIBeatmapSet;
// We only want to notify the user if a new challenge recently went live.
if (room.StartDate.Value != null
&& Math.Abs((DateTimeOffset.Now - room.StartDate.Value!.Value).TotalSeconds) < 1800
&& room.RoomID.Value != lastNotifiedDailyChallengeRoomId)
if (room.StartDate.Value != null && room.RoomID.Value != lastDailyChallengeRoomID)
{
lastNotifiedDailyChallengeRoomId = room.RoomID.Value;
notificationOverlay?.Post(new NewDailyChallengeNotification(room));
lastDailyChallengeRoomID = room.RoomID.Value;
// new challenge is live, reset intro played static.
statics.SetValue(Static.DailyChallengeIntroPlayed, false);
// we only want to notify the user if the new challenge just went live.
if (Math.Abs((DateTimeOffset.Now - room.StartDate.Value!.Value).TotalSeconds) < 1800)
notificationOverlay?.Post(new NewDailyChallengeNotification(room));
}
updateCountdown();

View File

@ -148,7 +148,10 @@ namespace osu.Game.Screens.Menu
OnPlaylists = () => this.Push(new Playlists()),
OnDailyChallenge = room =>
{
this.Push(new DailyChallengeIntro(room));
if (statics.Get<bool>(Static.DailyChallengeIntroPlayed))
this.Push(new DailyChallenge(room));
else
this.Push(new DailyChallengeIntro(room));
},
OnExit = () =>
{

View File

@ -70,6 +70,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
[Resolved]
private MusicController musicController { get; set; } = null!;
[Resolved]
private SessionStatics statics { get; set; } = null!;
private Sample? dateWindupSample;
private Sample? dateImpactSample;
private Sample? beatmapWindupSample;
@ -462,6 +465,8 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
{
Schedule(() =>
{
statics.SetValue(Static.DailyChallengeIntroPlayed, true);
if (this.IsCurrentScreen())
this.Push(new DailyChallenge(room));
});

View File

@ -19,6 +19,7 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Beatmaps;
using osu.Game.Utils;
namespace osu.Game.Tests.Visual.OnlinePlay
{
@ -278,11 +279,18 @@ namespace osu.Game.Tests.Visual.OnlinePlay
var result = JsonConvert.DeserializeObject<Room>(JsonConvert.SerializeObject(source));
Debug.Assert(result != null);
// Playlist item IDs aren't serialised.
// Playlist item IDs and beatmaps aren't serialised.
if (source.CurrentPlaylistItem.Value != null)
{
result.CurrentPlaylistItem.Value = result.CurrentPlaylistItem.Value.With(new Optional<IBeatmapInfo>(source.CurrentPlaylistItem.Value.Beatmap));
result.CurrentPlaylistItem.Value.ID = source.CurrentPlaylistItem.Value.ID;
}
for (int i = 0; i < source.Playlist.Count; i++)
{
result.Playlist[i] = result.Playlist[i].With(new Optional<IBeatmapInfo>(source.Playlist[i].Beatmap));
result.Playlist[i].ID = source.Playlist[i].ID;
}
return result;
}

View File

@ -22,7 +22,7 @@ namespace osu.Game.Utils
/// </remarks>
public readonly bool HasValue;
private Optional(T value)
public Optional(T value)
{
Value = value;
HasValue = true;