mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 19:42:55 +08:00
Simplify UserActivity
for serialisability over the wire
Up until now, the `UserActivity` class hierarchy contained things like beatmap info, room info, full replay info, etc. While this was convenient, it is soon going to be less so, as the data is sent over the wire to the spectator server so that the user's activity can be broadcast to other clients. To counteract this without creating a second separate and slimmed-down class hierarchy, slim down the `UserActivity` structure to contain the bare minimum amounts of data such that the structures aren't overly large and complex to serialise, but also contain enough data that they can be used by receiving clients directly without having to do beatmap or score lookups.
This commit is contained in:
parent
6d64538d7a
commit
cb823f367f
@ -9,7 +9,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Online.API;
|
||||
@ -95,17 +94,18 @@ namespace osu.Desktop
|
||||
|
||||
if (status.Value is UserStatusOnline && activity.Value != null)
|
||||
{
|
||||
presence.State = truncate(activity.Value.GetStatus(privacyMode.Value == DiscordRichPresenceMode.Limited));
|
||||
presence.Details = truncate(getDetails(activity.Value));
|
||||
bool hideIdentifiableInformation = privacyMode.Value == DiscordRichPresenceMode.Limited;
|
||||
presence.State = truncate(activity.Value.GetStatus(hideIdentifiableInformation));
|
||||
presence.Details = truncate(activity.Value.GetDetails(hideIdentifiableInformation) ?? string.Empty);
|
||||
|
||||
if (getBeatmap(activity.Value) is IBeatmapInfo beatmap && beatmap.OnlineID > 0)
|
||||
if (getBeatmapID(activity.Value) is int beatmapId && beatmapId > 0)
|
||||
{
|
||||
presence.Buttons = new[]
|
||||
{
|
||||
new Button
|
||||
{
|
||||
Label = "View beatmap",
|
||||
Url = $@"{api.WebsiteRootUrl}/beatmapsets/{beatmap.BeatmapSet?.OnlineID}#{ruleset.Value.ShortName}/{beatmap.OnlineID}"
|
||||
Url = $@"{api.WebsiteRootUrl}/beatmaps/{beatmapId}?mode={ruleset.Value.ShortName}"
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -159,40 +159,20 @@ namespace osu.Desktop
|
||||
});
|
||||
}
|
||||
|
||||
private IBeatmapInfo? getBeatmap(UserActivity activity)
|
||||
private int? getBeatmapID(UserActivity activity)
|
||||
{
|
||||
switch (activity)
|
||||
{
|
||||
case UserActivity.InGame game:
|
||||
return game.BeatmapInfo;
|
||||
return game.BeatmapID;
|
||||
|
||||
case UserActivity.EditingBeatmap edit:
|
||||
return edit.BeatmapInfo;
|
||||
return edit.BeatmapID;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private string getDetails(UserActivity activity)
|
||||
{
|
||||
switch (activity)
|
||||
{
|
||||
case UserActivity.InGame game:
|
||||
return game.BeatmapInfo.ToString() ?? string.Empty;
|
||||
|
||||
case UserActivity.EditingBeatmap edit:
|
||||
return edit.BeatmapInfo.ToString() ?? string.Empty;
|
||||
|
||||
case UserActivity.WatchingReplay watching:
|
||||
return watching.BeatmapInfo?.ToString() ?? string.Empty;
|
||||
|
||||
case UserActivity.InLobby lobby:
|
||||
return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
client.Dispose();
|
||||
|
@ -7,7 +7,6 @@ using System.Text;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
@ -33,9 +32,6 @@ namespace osu.Game.Online.Chat
|
||||
[Resolved]
|
||||
private IBindable<RulesetInfo> currentRuleset { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private LocalisationManager localisation { get; set; } = null!;
|
||||
|
||||
private readonly Channel? target;
|
||||
|
||||
/// <summary>
|
||||
@ -52,23 +48,28 @@ namespace osu.Game.Online.Chat
|
||||
base.LoadComplete();
|
||||
|
||||
string verb;
|
||||
IBeatmapInfo beatmapInfo;
|
||||
|
||||
int beatmapOnlineID;
|
||||
string beatmapDisplayTitle;
|
||||
|
||||
switch (api.Activity.Value)
|
||||
{
|
||||
case UserActivity.InGame game:
|
||||
verb = "playing";
|
||||
beatmapInfo = game.BeatmapInfo;
|
||||
beatmapOnlineID = game.BeatmapID;
|
||||
beatmapDisplayTitle = game.BeatmapDisplayTitle;
|
||||
break;
|
||||
|
||||
case UserActivity.EditingBeatmap edit:
|
||||
verb = "editing";
|
||||
beatmapInfo = edit.BeatmapInfo;
|
||||
beatmapOnlineID = edit.BeatmapID;
|
||||
beatmapDisplayTitle = edit.BeatmapDisplayTitle;
|
||||
break;
|
||||
|
||||
default:
|
||||
verb = "listening to";
|
||||
beatmapInfo = currentBeatmap.Value.BeatmapInfo;
|
||||
beatmapOnlineID = currentBeatmap.Value.BeatmapInfo.OnlineID;
|
||||
beatmapDisplayTitle = currentBeatmap.Value.BeatmapInfo.GetDisplayTitle();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -86,9 +87,7 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
string getBeatmapPart()
|
||||
{
|
||||
string beatmapInfoString = localisation.GetLocalisedBindableString(beatmapInfo.GetDisplayTitleRomanisable()).Value;
|
||||
|
||||
return beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfoString}]" : beatmapInfoString;
|
||||
return beatmapOnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapOnlineID} {beatmapDisplayTitle}]" : beatmapDisplayTitle;
|
||||
}
|
||||
|
||||
string getRulesetPart()
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.Countdown;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online
|
||||
{
|
||||
@ -18,6 +19,7 @@ namespace osu.Game.Online
|
||||
{
|
||||
internal static readonly IReadOnlyList<(Type derivedType, Type baseType)> BASE_TYPE_MAPPING = new[]
|
||||
{
|
||||
// multiplayer
|
||||
(typeof(ChangeTeamRequest), typeof(MatchUserRequest)),
|
||||
(typeof(StartMatchCountdownRequest), typeof(MatchUserRequest)),
|
||||
(typeof(StopCountdownRequest), typeof(MatchUserRequest)),
|
||||
@ -28,6 +30,20 @@ namespace osu.Game.Online
|
||||
(typeof(MatchStartCountdown), typeof(MultiplayerCountdown)),
|
||||
(typeof(ForceGameplayStartCountdown), typeof(MultiplayerCountdown)),
|
||||
(typeof(ServerShuttingDownCountdown), typeof(MultiplayerCountdown)),
|
||||
|
||||
// metadata
|
||||
(typeof(UserActivity.ChoosingBeatmap), typeof(UserActivity)),
|
||||
(typeof(UserActivity.InSoloGame), typeof(UserActivity)),
|
||||
(typeof(UserActivity.WatchingReplay), typeof(UserActivity)),
|
||||
(typeof(UserActivity.SpectatingUser), typeof(UserActivity)),
|
||||
(typeof(UserActivity.SearchingForLobby), typeof(UserActivity)),
|
||||
(typeof(UserActivity.InLobby), typeof(UserActivity)),
|
||||
(typeof(UserActivity.InMultiplayerGame), typeof(UserActivity)),
|
||||
(typeof(UserActivity.SpectatingMultiplayerGame), typeof(UserActivity)),
|
||||
(typeof(UserActivity.InPlaylistGame), typeof(UserActivity)),
|
||||
(typeof(UserActivity.EditingBeatmap), typeof(UserActivity)),
|
||||
(typeof(UserActivity.ModdingBeatmap), typeof(UserActivity)),
|
||||
(typeof(UserActivity.TestingBeatmap), typeof(UserActivity)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
// 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;
|
||||
using MessagePack;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
@ -10,43 +13,84 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Users
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all structures describing the user's current activity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Warning: keep <see cref="UnionAttribute"/> specs consistent with
|
||||
/// <see cref="SignalRWorkaroundTypes.BASE_TYPE_MAPPING"/>.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
[Union(11, typeof(ChoosingBeatmap))]
|
||||
[Union(12, typeof(InSoloGame))]
|
||||
[Union(13, typeof(WatchingReplay))]
|
||||
[Union(14, typeof(SpectatingUser))]
|
||||
[Union(21, typeof(SearchingForLobby))]
|
||||
[Union(22, typeof(InLobby))]
|
||||
[Union(23, typeof(InMultiplayerGame))]
|
||||
[Union(24, typeof(SpectatingMultiplayerGame))]
|
||||
[Union(31, typeof(InPlaylistGame))]
|
||||
[Union(41, typeof(EditingBeatmap))]
|
||||
[Union(42, typeof(ModdingBeatmap))]
|
||||
[Union(43, typeof(TestingBeatmap))]
|
||||
public abstract class UserActivity
|
||||
{
|
||||
public abstract string GetStatus(bool hideIdentifiableInformation = false);
|
||||
public virtual string? GetDetails(bool hideIdentifiableInformation = false) => null;
|
||||
|
||||
public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker;
|
||||
|
||||
public class ModdingBeatmap : EditingBeatmap
|
||||
{
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a beatmap";
|
||||
public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark;
|
||||
|
||||
public ModdingBeatmap(IBeatmapInfo info)
|
||||
: base(info)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class ChoosingBeatmap : UserActivity
|
||||
{
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => "Choosing a beatmap";
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public abstract class InGame : UserActivity
|
||||
{
|
||||
public IBeatmapInfo BeatmapInfo { get; }
|
||||
[Key(0)]
|
||||
public int BeatmapID { get; set; }
|
||||
|
||||
public IRulesetInfo Ruleset { get; }
|
||||
[Key(1)]
|
||||
public string BeatmapDisplayTitle { get; set; } = string.Empty;
|
||||
|
||||
[Key(2)]
|
||||
public int RulesetID { get; set; }
|
||||
|
||||
[Key(3)]
|
||||
public string RulesetPlayingVerb { get; set; } = string.Empty; // TODO: i'm going with this for now, but this is wasteful
|
||||
|
||||
protected InGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
{
|
||||
BeatmapInfo = beatmapInfo;
|
||||
Ruleset = ruleset;
|
||||
BeatmapID = beatmapInfo.OnlineID;
|
||||
BeatmapDisplayTitle = beatmapInfo.GetDisplayTitle();
|
||||
|
||||
RulesetID = ruleset.OnlineID;
|
||||
RulesetPlayingVerb = ruleset.CreateInstance().PlayingVerb;
|
||||
}
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => Ruleset.CreateInstance().PlayingVerb;
|
||||
[SerializationConstructor]
|
||||
protected InGame() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => RulesetPlayingVerb;
|
||||
public override string GetDetails(bool hideIdentifiableInformation = false) => BeatmapDisplayTitle;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class InSoloGame : InGame
|
||||
{
|
||||
public InSoloGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
: base(beatmapInfo, ruleset)
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public InSoloGame() { }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class InMultiplayerGame : InGame
|
||||
{
|
||||
public InMultiplayerGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
@ -54,9 +98,122 @@ namespace osu.Game.Users
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public InMultiplayerGame()
|
||||
{
|
||||
}
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => $@"{base.GetStatus(hideIdentifiableInformation)} with others";
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class InPlaylistGame : InGame
|
||||
{
|
||||
public InPlaylistGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
: base(beatmapInfo, ruleset)
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public InPlaylistGame() { }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class TestingBeatmap : InGame
|
||||
{
|
||||
public TestingBeatmap(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
: base(beatmapInfo, ruleset)
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public TestingBeatmap() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => "Testing a beatmap";
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class EditingBeatmap : UserActivity
|
||||
{
|
||||
[Key(0)]
|
||||
public int BeatmapID { get; set; }
|
||||
|
||||
[Key(1)]
|
||||
public string BeatmapDisplayTitle { get; set; } = string.Empty;
|
||||
|
||||
public EditingBeatmap(IBeatmapInfo info)
|
||||
{
|
||||
BeatmapID = info.OnlineID;
|
||||
BeatmapDisplayTitle = info.GetDisplayTitle();
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public EditingBeatmap() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => @"Editing a beatmap";
|
||||
public override string GetDetails(bool hideIdentifiableInformation = false) => BeatmapDisplayTitle;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class ModdingBeatmap : EditingBeatmap
|
||||
{
|
||||
public ModdingBeatmap(IBeatmapInfo info)
|
||||
: base(info)
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public ModdingBeatmap() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a beatmap";
|
||||
public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class WatchingReplay : UserActivity
|
||||
{
|
||||
[Key(0)]
|
||||
public long ScoreID { get; set; }
|
||||
|
||||
[Key(1)]
|
||||
public string PlayerName { get; set; } = string.Empty;
|
||||
|
||||
[Key(2)]
|
||||
public int BeatmapID { get; set; }
|
||||
|
||||
[Key(3)]
|
||||
public string? BeatmapDisplayTitle { get; set; }
|
||||
|
||||
public WatchingReplay(ScoreInfo score)
|
||||
{
|
||||
ScoreID = score.OnlineID;
|
||||
PlayerName = score.User.Username;
|
||||
BeatmapID = score.BeatmapInfo?.OnlineID ?? -1;
|
||||
BeatmapDisplayTitle = score.BeatmapInfo?.GetDisplayTitle();
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public WatchingReplay() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a replay" : $@"Watching {PlayerName}'s replay";
|
||||
public override string? GetDetails(bool hideIdentifiableInformation = false) => BeatmapDisplayTitle;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class SpectatingUser : WatchingReplay
|
||||
{
|
||||
public SpectatingUser(ScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public SpectatingUser() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a user" : $@"Spectating {PlayerName}";
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class SpectatingMultiplayerGame : InGame
|
||||
{
|
||||
public SpectatingMultiplayerGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
@ -64,88 +221,41 @@ namespace osu.Game.Users
|
||||
{
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public SpectatingMultiplayerGame() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => $"Watching others {base.GetStatus(hideIdentifiableInformation).ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
public class InPlaylistGame : InGame
|
||||
{
|
||||
public InPlaylistGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
: base(beatmapInfo, ruleset)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class InSoloGame : InGame
|
||||
{
|
||||
public InSoloGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
: base(beatmapInfo, ruleset)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class TestingBeatmap : InGame
|
||||
{
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => "Testing a beatmap";
|
||||
|
||||
public TestingBeatmap(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
||||
: base(beatmapInfo, ruleset)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class EditingBeatmap : UserActivity
|
||||
{
|
||||
public IBeatmapInfo BeatmapInfo { get; }
|
||||
|
||||
public EditingBeatmap(IBeatmapInfo info)
|
||||
{
|
||||
BeatmapInfo = info;
|
||||
}
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => @"Editing a beatmap";
|
||||
}
|
||||
|
||||
public class WatchingReplay : UserActivity
|
||||
{
|
||||
private readonly ScoreInfo score;
|
||||
|
||||
protected string Username => score.User.Username;
|
||||
|
||||
public BeatmapInfo? BeatmapInfo => score.BeatmapInfo;
|
||||
|
||||
public WatchingReplay(ScoreInfo score)
|
||||
{
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a replay" : $@"Watching {Username}'s replay";
|
||||
}
|
||||
|
||||
public class SpectatingUser : WatchingReplay
|
||||
{
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a user" : $@"Spectating {Username}";
|
||||
|
||||
public SpectatingUser(ScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class SearchingForLobby : UserActivity
|
||||
{
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => @"Looking for a lobby";
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class InLobby : UserActivity
|
||||
{
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => @"In a lobby";
|
||||
[Key(0)]
|
||||
public long RoomID { get; set; }
|
||||
|
||||
public readonly Room Room;
|
||||
[Key(1)]
|
||||
public string RoomName { get; set; } = string.Empty;
|
||||
|
||||
public InLobby(Room room)
|
||||
{
|
||||
Room = room;
|
||||
RoomID = room.RoomID.Value ?? -1;
|
||||
RoomName = room.Name.Value;
|
||||
}
|
||||
|
||||
[SerializationConstructor]
|
||||
public InLobby() { }
|
||||
|
||||
public override string GetStatus(bool hideIdentifiableInformation = false) => @"In a lobby";
|
||||
|
||||
public override string? GetDetails(bool hideIdentifiableInformation = false) => hideIdentifiableInformation
|
||||
? null
|
||||
: RoomName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user