diff --git a/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs b/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs new file mode 100644 index 000000000..a7d13235f --- /dev/null +++ b/src/Discord.Net.Core/Entities/Activities/ActivityProperties.cs @@ -0,0 +1,38 @@ +using System; + +namespace Discord +{ + /// + /// Flags for the property, that are ORd together. + /// These describe what the activity payload includes. + /// + [Flags] + public enum ActivityProperties + { + /// + /// Indicates that no actions on this activity can be taken. + /// + None = 0, + Instance = 1, + /// + /// Indicates that this activity can be joined. + /// + Join = 0b10, + /// + /// Indicates that this activity can be spectated. + /// + Spectate = 0b100, + /// + /// Indicates that a user may request to join an activity. + /// + JoinRequest = 0b1000, + /// + /// Indicates that a user can listen along in Spotify. + /// + Sync = 0b10000, + /// + /// Indicates that a user can play this song. + /// + Play = 0b100000 + } +} diff --git a/src/Discord.Net.Core/Entities/Activities/Game.cs b/src/Discord.Net.Core/Entities/Activities/Game.cs index f232cc5bf..8891e142c 100644 --- a/src/Discord.Net.Core/Entities/Activities/Game.cs +++ b/src/Discord.Net.Core/Entities/Activities/Game.cs @@ -12,6 +12,10 @@ namespace Discord public string Name { get; internal set; } /// public ActivityType Type { get; internal set; } + /// + public ActivityProperties Flags { get; internal set; } + /// + public string Details { get; internal set; } internal Game() { } /// @@ -19,10 +23,12 @@ namespace Discord /// /// The name of the game. /// The type of activity. - public Game(string name, ActivityType type = ActivityType.Playing) + public Game(string name, ActivityType type = ActivityType.Playing, ActivityProperties flags = ActivityProperties.None, string details = null) { Name = name; Type = type; + Flags = flags; + Details = details; } /// Returns the name of the . diff --git a/src/Discord.Net.Core/Entities/Activities/IActivity.cs b/src/Discord.Net.Core/Entities/Activities/IActivity.cs index ac0c1b5d7..96704b826 100644 --- a/src/Discord.Net.Core/Entities/Activities/IActivity.cs +++ b/src/Discord.Net.Core/Entities/Activities/IActivity.cs @@ -19,5 +19,22 @@ namespace Discord /// The type of activity. /// ActivityType Type { get; } + /// + /// Gets the flags that are relevant to this activity. + /// + /// + /// This value is determined by bitwise OR-ing values together. + /// + /// + /// The value of flags for this activity. + /// + ActivityProperties Flags { get; } + /// + /// Gets the details on what the player is currently doing. + /// + /// + /// A string describing what the player is doing. + /// + string Details { get; } } } diff --git a/src/Discord.Net.Core/Entities/Activities/RichGame.cs b/src/Discord.Net.Core/Entities/Activities/RichGame.cs index 2455fd557..2da8d741c 100644 --- a/src/Discord.Net.Core/Entities/Activities/RichGame.cs +++ b/src/Discord.Net.Core/Entities/Activities/RichGame.cs @@ -11,10 +11,6 @@ namespace Discord internal RichGame() { } /// - /// Gets what the player is currently doing. - /// - public string Details { get; internal set; } - /// /// Gets the user's current party status. /// public string State { get; internal set; } diff --git a/src/Discord.Net.Core/Entities/Users/ISelfUser.cs b/src/Discord.Net.Core/Entities/Users/ISelfUser.cs index c1d7874eb..04c655212 100644 --- a/src/Discord.Net.Core/Entities/Users/ISelfUser.cs +++ b/src/Discord.Net.Core/Entities/Users/ISelfUser.cs @@ -26,6 +26,34 @@ namespace Discord /// true if this user has enabled multi-factor authentication on their account; false if not. /// bool IsMfaEnabled { get; } + /// + /// Gets the flags that are applied to a user's account. + /// + /// + /// This value is determined by bitwise OR-ing values together. + /// + /// + /// The value of flags for this user. + /// + UserProperties Flags { get; } + /// + /// Gets the type of Nitro subscription that is active on this user's account. + /// + /// + /// This information may only be available with the identify OAuth scope. + /// + /// + /// The type of Nitro subscription the user subscribes to, if any. + /// + PremiumType PremiumType { get; } + /// + /// Gets the user's chosen language option. + /// + /// + /// The IETF language tag of the user's chosen region, if provided. + /// For example, a locale of "English, US" is "en-US", "Chinese (Taiwan)" is "zh-TW", etc. + /// + string Locale { get; } /// /// Modifies the user's properties. diff --git a/src/Discord.Net.Core/Entities/Users/PremiumType.cs b/src/Discord.Net.Core/Entities/Users/PremiumType.cs new file mode 100644 index 000000000..2b41e0b6a --- /dev/null +++ b/src/Discord.Net.Core/Entities/Users/PremiumType.cs @@ -0,0 +1,21 @@ +namespace Discord +{ + /// + /// Specifies the type of subscription a user is subscribed to. + /// + public enum PremiumType + { + /// + /// No subscription. + /// + None = 0, + /// + /// Nitro Classic subscription. Includes app perks like animated emojis and avatars, but not games. + /// + NitroClassic = 1, + /// + /// Nitro subscription. Includes app perks as well as the games subscription service. + /// + Nitro = 2 + } +} diff --git a/src/Discord.Net.Core/Entities/Users/UserProperties.cs b/src/Discord.Net.Core/Entities/Users/UserProperties.cs new file mode 100644 index 000000000..4f7272daa --- /dev/null +++ b/src/Discord.Net.Core/Entities/Users/UserProperties.cs @@ -0,0 +1,41 @@ +using System; + +namespace Discord +{ + [Flags] + public enum UserProperties + { + /// + /// Default value for flags, when none are given to an account. + /// + None = 0, + /// + /// Flag given to Discord staff. + /// + Staff = 0b1, + /// + /// Flag given to Discord partners. + /// + Partner = 0b10, + /// + /// Flag given to users who have participated in the bug report program. + /// + BugHunter = 0b1000, + /// + /// Flag given to users who are in the HypeSquad House of Bravery. + /// + HypeSquadBravery = 0b100_0000, + /// + /// Flag given to users who are in the HypeSquad House of Brilliance. + /// + HypeSquadBrilliance = 0b1000_0000, + /// + /// Flag given to users who are in the HypeSquad House of Balance. + /// + HypeSquadBalance = 0b1_0000_0000, + /// + /// Flag given to users who subscribed to Nitro before games were added. + /// + EarlySupporter = 0b10_0000_0000, + } +} diff --git a/src/Discord.Net.Rest/API/Common/Game.cs b/src/Discord.Net.Rest/API/Common/Game.cs index 4cde8444a..2ec1e3846 100644 --- a/src/Discord.Net.Rest/API/Common/Game.cs +++ b/src/Discord.Net.Rest/API/Common/Game.cs @@ -33,6 +33,8 @@ namespace Discord.API public Optional SyncId { get; set; } [JsonProperty("session_id")] public Optional SessionId { get; set; } + [JsonProperty("Flags")] + public Optional Flags { get; set; } [OnError] internal void OnError(StreamingContext context, ErrorContext errorContext) diff --git a/src/Discord.Net.Rest/API/Common/User.cs b/src/Discord.Net.Rest/API/Common/User.cs index d49d24623..2eff3753d 100644 --- a/src/Discord.Net.Rest/API/Common/User.cs +++ b/src/Discord.Net.Rest/API/Common/User.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CS1591 using Newtonsoft.Json; namespace Discord.API @@ -23,5 +23,11 @@ namespace Discord.API public Optional Email { get; set; } [JsonProperty("mfa_enabled")] public Optional MfaEnabled { get; set; } + [JsonProperty("flags")] + public Optional Flags { get; set; } + [JsonProperty("premium_type")] + public Optional PremiumType { get; set; } + [JsonProperty("locale")] + public Optional Locale { get; set; } } } diff --git a/src/Discord.Net.Rest/Entities/Users/RestSelfUser.cs b/src/Discord.Net.Rest/Entities/Users/RestSelfUser.cs index 7f3a3faa8..b5ef01c53 100644 --- a/src/Discord.Net.Rest/Entities/Users/RestSelfUser.cs +++ b/src/Discord.Net.Rest/Entities/Users/RestSelfUser.cs @@ -17,6 +17,12 @@ namespace Discord.Rest public bool IsVerified { get; private set; } /// public bool IsMfaEnabled { get; private set; } + /// + public UserProperties Flags { get; private set; } + /// + public PremiumType PremiumType { get; private set; } + /// + public string Locale { get; private set; } internal RestSelfUser(BaseDiscordClient discord, ulong id) : base(discord, id) @@ -39,6 +45,12 @@ namespace Discord.Rest IsVerified = model.Verified.Value; if (model.MfaEnabled.IsSpecified) IsMfaEnabled = model.MfaEnabled.Value; + if (model.Flags.IsSpecified) + Flags = (UserProperties)model.Flags.Value; + if (model.PremiumType.IsSpecified) + PremiumType = model.PremiumType.Value; + if (model.Locale.IsSpecified) + Locale = model.Locale.Value; } /// diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index ae705109c..7b11257a3 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -30,6 +30,12 @@ namespace Discord.WebSocket public override string AvatarId { get { return GlobalUser.AvatarId; } internal set { GlobalUser.AvatarId = value; } } /// internal override SocketPresence Presence { get { return GlobalUser.Presence; } set { GlobalUser.Presence = value; } } + /// + public UserProperties Flags { get; internal set; } + /// + public PremiumType PremiumType { get; internal set; } + /// + public string Locale { get; internal set; } /// public override bool IsWebhook => false; @@ -63,6 +69,21 @@ namespace Discord.WebSocket IsMfaEnabled = model.MfaEnabled.Value; hasGlobalChanges = true; } + if (model.Flags.IsSpecified && model.Flags.Value != Flags) + { + Flags = (UserProperties)model.Flags.Value; + hasGlobalChanges = true; + } + if (model.PremiumType.IsSpecified && model.PremiumType.Value != PremiumType) + { + PremiumType = model.PremiumType.Value; + hasGlobalChanges = true; + } + if (model.Locale.IsSpecified && model.Locale.Value != Locale) + { + Locale = model.Locale.Value; + hasGlobalChanges = true; + } return hasGlobalChanges; } diff --git a/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs b/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs index e8dc4b5f0..fd91ba987 100644 --- a/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs +++ b/src/Discord.Net.WebSocket/Extensions/EntityExtensions.cs @@ -25,7 +25,8 @@ namespace Discord.WebSocket Artists = model.State.GetValueOrDefault()?.Split(';').Select(x=>x?.Trim()).ToImmutableArray(), Duration = timestamps?.End - timestamps?.Start, AlbumArtUrl = albumArtId != null ? CDN.GetSpotifyAlbumArtUrl(albumArtId) : null, - Type = ActivityType.Listening + Type = ActivityType.Listening, + Flags = model.Flags.GetValueOrDefault(), }; } @@ -44,18 +45,25 @@ namespace Discord.WebSocket LargeAsset = assets?[1], Party = model.Party.IsSpecified ? model.Party.Value.ToEntity() : null, Secrets = model.Secrets.IsSpecified ? model.Secrets.Value.ToEntity() : null, - Timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null + Timestamps = model.Timestamps.IsSpecified ? model.Timestamps.Value.ToEntity() : null, + Flags = model.Flags.GetValueOrDefault() }; } // Stream Game if (model.StreamUrl.IsSpecified) { return new StreamingGame( - model.Name, - model.StreamUrl.Value); + model.Name, + model.StreamUrl.Value) + { + Flags = model.Flags.GetValueOrDefault(), + Details = model.Details.GetValueOrDefault() + }; } // Normal Game - return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing); + return new Game(model.Name, model.Type.GetValueOrDefault() ?? ActivityType.Playing, + model.Flags.IsSpecified ? model.Flags.Value : ActivityProperties.None, + model.Details.GetValueOrDefault()); } // (Small, Large)