From d5b2d9ce9722c3127d4252e4b6b92388f758ba03 Mon Sep 17 00:00:00 2001 From: tsrk Date: Sun, 5 Feb 2023 23:58:08 +0000 Subject: [PATCH 1/8] feat: add support for spectating status --- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 3 +++ osu.Game/Users/UserActivity.cs | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 240fbcf662..bd9e3917a5 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Screens; using osu.Game.Online.Spectator; using osu.Game.Scoring; +using osu.Game.Users; namespace osu.Game.Screens.Play { @@ -14,6 +15,8 @@ namespace osu.Game.Screens.Play { private readonly Score score; + protected override UserActivity InitialActivity => new UserActivity.Spectating(score.ScoreInfo.User); + public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) { diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 6de797ca3a..950c486f22 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -5,6 +5,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osuTK.Graphics; @@ -92,7 +93,14 @@ namespace osu.Game.Users public class Spectating : UserActivity { - public override string Status => @"Spectating a game"; + private readonly APIUser user; + + public Spectating(APIUser user) + { + this.user = user; + } + + public override string Status => @$"Spectating {user.Username}"; } public class SearchingForLobby : UserActivity From bf273597ea726ef7d493b8db17889b9f0c93561c Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 00:41:10 +0000 Subject: [PATCH 2/8] feat: actually support status also for Replays --- osu.Game/Screens/Play/ReplayPlayer.cs | 3 +++ osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Users/UserActivity.cs | 16 ++++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index c5ef6b1585..e2b8ad7011 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; +using osu.Game.Users; namespace osu.Game.Screens.Play { @@ -24,6 +25,8 @@ namespace osu.Game.Screens.Play private readonly bool replayIsFailedScore; + protected override UserActivity InitialActivity => new UserActivity.Watching(); + // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) protected override bool CheckModsAllowFailure() { diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index bd9e3917a5..65b66166c0 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play { private readonly Score score; - protected override UserActivity InitialActivity => new UserActivity.Spectating(score.ScoreInfo.User); + protected override UserActivity InitialActivity => new UserActivity.Spectating(); public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 950c486f22..d652730621 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -5,7 +5,6 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osuTK.Graphics; @@ -91,16 +90,17 @@ namespace osu.Game.Users public override string Status => @"Editing a beatmap"; } - public class Spectating : UserActivity + public class Watching : UserActivity { - private readonly APIUser user; + protected virtual string Verb => @"Watching"; - public Spectating(APIUser user) - { - this.user = user; - } + public override string Status => @$"{Verb} a game"; + } - public override string Status => @$"Spectating {user.Username}"; + public class Spectating : Watching + { + protected override string Verb => @"Spectating"; + public override string Status => @$"{Verb} a game"; } public class SearchingForLobby : UserActivity From e878bb42a4670796186cd5c926cea35cf1b36039 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 00:53:56 +0000 Subject: [PATCH 3/8] test: add test for watching activity --- osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 4c1df850b2..eaf2ca5ac0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -107,6 +107,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("set online status", () => status.Value = new UserStatusOnline()); AddStep("idle", () => activity.Value = null); + AddStep("watching", () => activity.Value = new UserActivity.Watching()); AddStep("spectating", () => activity.Value = new UserActivity.Spectating()); AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0)); AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1)); From b3f38b0f4c463c147dc3a646fe02f6270e597283 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 00:56:11 +0000 Subject: [PATCH 4/8] quality: remove redundant `Status` override --- osu.Game/Users/UserActivity.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index d652730621..37b5a2bf1e 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -100,7 +100,6 @@ namespace osu.Game.Users public class Spectating : Watching { protected override string Verb => @"Spectating"; - public override string Status => @$"{Verb} a game"; } public class SearchingForLobby : UserActivity From bc89f8dc5b9d40aa92bcc88249e7165e4b72f9fc Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 12:44:00 +0000 Subject: [PATCH 5/8] feat: add name and rulset verb display support --- osu.Desktop/DiscordRichPresence.cs | 5 +++- .../Visual/Online/TestSceneUserPanel.cs | 14 ++++++++-- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Users/UserActivity.cs | 28 ++++++++++++++++++- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 2c4577f239..6ca86c64c4 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -98,7 +98,7 @@ namespace osu.Desktop if (status.Value is UserStatusOnline && activity.Value != null) { - presence.State = truncate(activity.Value.Status); + presence.State = truncate(privacyMode.Value == DiscordRichPresenceMode.Limited ? activity.Value.LimitedStatus : activity.Value.Status); presence.Details = truncate(getDetails(activity.Value)); if (getBeatmap(activity.Value) is IBeatmapInfo beatmap && beatmap.OnlineID > 0) @@ -186,6 +186,9 @@ namespace osu.Desktop case UserActivity.Editing edit: return edit.BeatmapInfo.ToString() ?? string.Empty; + case UserActivity.Watching watching: + return watching.BeatmapInfo.ToString(); + case UserActivity.InLobby lobby: return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index eaf2ca5ac0..64a42ee6ce 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -11,6 +11,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; +using osu.Game.Scoring; +using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK; @@ -107,8 +109,8 @@ namespace osu.Game.Tests.Visual.Online AddStep("set online status", () => status.Value = new UserStatusOnline()); AddStep("idle", () => activity.Value = null); - AddStep("watching", () => activity.Value = new UserActivity.Watching()); - AddStep("spectating", () => activity.Value = new UserActivity.Spectating()); + AddStep("watching", () => activity.Value = new UserActivity.Watching(createScore(@"nats"))); + AddStep("spectating", () => activity.Value = new UserActivity.Spectating(createScore(@"mrekk"))); AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0)); AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1)); AddStep("solo (osu!catch)", () => activity.Value = soloGameStatusForRuleset(2)); @@ -133,6 +135,14 @@ namespace osu.Game.Tests.Visual.Online private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.InSoloGame(null, rulesetStore.GetRuleset(rulesetId)); + private ScoreInfo createScore(string name) => new ScoreInfo(new TestBeatmap(Ruleset.Value).BeatmapInfo) + { + User = new APIUser + { + Username = name, + } + }; + private partial class TestUserListPanel : UserListPanel { public TestUserListPanel(APIUser user) diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index e2b8ad7011..9e87969687 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play private readonly bool replayIsFailedScore; - protected override UserActivity InitialActivity => new UserActivity.Watching(); + protected override UserActivity InitialActivity => new UserActivity.Watching(Score.ScoreInfo); // Disallow replays from failing. (see https://github.com/ppy/osu/issues/6108) protected override bool CheckModsAllowFailure() diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 65b66166c0..8a9cda2af7 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play { private readonly Score score; - protected override UserActivity InitialActivity => new UserActivity.Spectating(); + protected override UserActivity InitialActivity => new UserActivity.Spectating(Score.ScoreInfo); public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(score, configuration) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 37b5a2bf1e..99d68e7564 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -4,9 +4,11 @@ #nullable disable using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Rulesets; +using osu.Game.Scoring; using osuTK.Graphics; namespace osu.Game.Users @@ -14,6 +16,12 @@ namespace osu.Game.Users public abstract class UserActivity { public abstract string Status { get; } + + /// + /// This property is used when the is + /// + public virtual string LimitedStatus => Status; + public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker; public class Modding : UserActivity @@ -92,14 +100,32 @@ namespace osu.Game.Users public class Watching : UserActivity { + private readonly ScoreInfo score; + + private string username => score.User.Username; + private string playingVerb => score.BeatmapInfo.Ruleset.CreateInstance().PlayingVerb; + + public BeatmapInfo BeatmapInfo => score.BeatmapInfo; + + public Watching(ScoreInfo score) + { + this.score = score; + } + protected virtual string Verb => @"Watching"; - public override string Status => @$"{Verb} a game"; + public override string Status => @$"{Verb} {username} {playingVerb.ToLowerInvariant()}"; + public override string LimitedStatus => $@"{Verb} a game"; } public class Spectating : Watching { protected override string Verb => @"Spectating"; + + public Spectating(ScoreInfo score) + : base(score) + { + } } public class SearchingForLobby : UserActivity From 1baaae35a9748c913a744c1c6fbdb4f90d7bdb08 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 20:07:16 +0000 Subject: [PATCH 6/8] quality: Simplify string --- osu.Game/Users/UserActivity.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 99d68e7564..b62cd7edd5 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -102,8 +102,7 @@ namespace osu.Game.Users { private readonly ScoreInfo score; - private string username => score.User.Username; - private string playingVerb => score.BeatmapInfo.Ruleset.CreateInstance().PlayingVerb; + protected string Username => score.User.Username; public BeatmapInfo BeatmapInfo => score.BeatmapInfo; @@ -112,15 +111,12 @@ namespace osu.Game.Users this.score = score; } - protected virtual string Verb => @"Watching"; - - public override string Status => @$"{Verb} {username} {playingVerb.ToLowerInvariant()}"; - public override string LimitedStatus => $@"{Verb} a game"; + public override string Status => $@"Watching {Username}"; } public class Spectating : Watching { - protected override string Verb => @"Spectating"; + public override string Status => $@"Spectating {Username}"; public Spectating(ScoreInfo score) : base(score) From da10166628e01a3cd607a9337edc8546c80cbdb8 Mon Sep 17 00:00:00 2001 From: tsrk Date: Mon, 6 Feb 2023 21:30:55 +0000 Subject: [PATCH 7/8] quality: convert getter property to method so that sensible information can be hidden via an argument --- osu.Desktop/DiscordRichPresence.cs | 2 +- osu.Game/Users/ExtendedUserPanel.cs | 2 +- osu.Game/Users/UserActivity.cs | 28 +++++++++++----------------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 6ca86c64c4..e24fe1a1ec 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -98,7 +98,7 @@ namespace osu.Desktop if (status.Value is UserStatusOnline && activity.Value != null) { - presence.State = truncate(privacyMode.Value == DiscordRichPresenceMode.Limited ? activity.Value.LimitedStatus : activity.Value.Status); + presence.State = truncate(activity.Value.GetStatus(privacyMode.Value == DiscordRichPresenceMode.Limited)); presence.Details = truncate(getDetails(activity.Value)); if (getBeatmap(activity.Value) is IBeatmapInfo beatmap && beatmap.OnlineID > 0) diff --git a/osu.Game/Users/ExtendedUserPanel.cs b/osu.Game/Users/ExtendedUserPanel.cs index 4ea3c036c1..3c1b68f9ef 100644 --- a/osu.Game/Users/ExtendedUserPanel.cs +++ b/osu.Game/Users/ExtendedUserPanel.cs @@ -106,7 +106,7 @@ namespace osu.Game.Users // Set status message based on activity (if we have one) and status is not offline if (activity != null && !(status is UserStatusOffline)) { - statusMessage.Text = activity.Status; + statusMessage.Text = activity.GetStatus(); statusIcon.FadeColour(activity.GetAppropriateColour(Colours), 500, Easing.OutQuint); return; } diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index b62cd7edd5..0e6e3ca5f2 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -4,7 +4,6 @@ #nullable disable using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.Rooms; using osu.Game.Rulesets; @@ -15,24 +14,19 @@ namespace osu.Game.Users { public abstract class UserActivity { - public abstract string Status { get; } - - /// - /// This property is used when the is - /// - public virtual string LimitedStatus => Status; + public abstract string GetStatus(bool hideIdentifiableInformation = false); public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker; public class Modding : UserActivity { - public override string Status => "Modding a map"; + public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a map"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark; } public class ChoosingBeatmap : UserActivity { - public override string Status => "Choosing a beatmap"; + public override string GetStatus(bool hideIdentifiableInformation = false) => "Choosing a beatmap"; } public abstract class InGame : UserActivity @@ -47,7 +41,7 @@ namespace osu.Game.Users Ruleset = ruleset; } - public override string Status => Ruleset.CreateInstance().PlayingVerb; + public override string GetStatus(bool hideIdentifiableInformation = false) => Ruleset.CreateInstance().PlayingVerb; } public class InMultiplayerGame : InGame @@ -57,7 +51,7 @@ namespace osu.Game.Users { } - public override string Status => $@"{base.Status} with others"; + public override string GetStatus(bool hideIdentifiableInformation = false) => $@"{base.GetStatus(hideIdentifiableInformation)} with others"; } public class SpectatingMultiplayerGame : InGame @@ -67,7 +61,7 @@ namespace osu.Game.Users { } - public override string Status => $"Watching others {base.Status.ToLowerInvariant()}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => $"Watching others {base.GetStatus(hideIdentifiableInformation).ToLowerInvariant()}"; } public class InPlaylistGame : InGame @@ -95,7 +89,7 @@ namespace osu.Game.Users BeatmapInfo = info; } - public override string Status => @"Editing a beatmap"; + public override string GetStatus(bool hideIdentifiableInformation = false) => @"Editing a beatmap"; } public class Watching : UserActivity @@ -111,12 +105,12 @@ namespace osu.Game.Users this.score = score; } - public override string Status => $@"Watching {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a game" : $@"Watching {Username}"; } public class Spectating : Watching { - public override string Status => $@"Spectating {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a game" : $@"Spectating {Username}"; public Spectating(ScoreInfo score) : base(score) @@ -126,12 +120,12 @@ namespace osu.Game.Users public class SearchingForLobby : UserActivity { - public override string Status => @"Looking for a lobby"; + public override string GetStatus(bool hideIdentifiableInformation = false) => @"Looking for a lobby"; } public class InLobby : UserActivity { - public override string Status => @"In a lobby"; + public override string GetStatus(bool hideIdentifiableInformation = false) => @"In a lobby"; public readonly Room Room; From 2c1154afc67966742980e498a89adca96698031f Mon Sep 17 00:00:00 2001 From: Ruki Date: Thu, 9 Feb 2023 17:15:30 +0000 Subject: [PATCH 8/8] refactor: improve wording Co-authored-by: Joseph Madamba --- osu.Game/Users/UserActivity.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 0e6e3ca5f2..b1c3fac382 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -105,12 +105,12 @@ namespace osu.Game.Users this.score = score; } - public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a game" : $@"Watching {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a replay" : $@"Watching {Username}'s replay"; } public class Spectating : Watching { - public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a game" : $@"Spectating {Username}"; + public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a user" : $@"Spectating {Username}"; public Spectating(ScoreInfo score) : base(score)