diff --git a/src/Discord.Net.Core/API/Rest/ModifyPresenceParams.cs b/src/Discord.Net.Core/API/Rest/ModifyPresenceParams.cs index 52145643a..ac55e2491 100644 --- a/src/Discord.Net.Core/API/Rest/ModifyPresenceParams.cs +++ b/src/Discord.Net.Core/API/Rest/ModifyPresenceParams.cs @@ -1,4 +1,6 @@ #pragma warning disable CS1591 +using System; + namespace Discord.API.Rest { public class ModifyPresenceParams diff --git a/src/Discord.Net.Core/Entities/Users/UserStatus.cs b/src/Discord.Net.Core/Entities/Users/UserStatus.cs index ea2c3680e..d183c139d 100644 --- a/src/Discord.Net.Core/Entities/Users/UserStatus.cs +++ b/src/Discord.Net.Core/Entities/Users/UserStatus.cs @@ -5,6 +5,7 @@ Unknown, Online, Idle, + AFK, DoNotDisturb, Invisible, Offline diff --git a/src/Discord.Net.Core/Net/Converters/UserStatusConverter.cs b/src/Discord.Net.Core/Net/Converters/UserStatusConverter.cs index 3b4e1c0cb..cbcc9eab2 100644 --- a/src/Discord.Net.Core/Net/Converters/UserStatusConverter.cs +++ b/src/Discord.Net.Core/Net/Converters/UserStatusConverter.cs @@ -38,6 +38,7 @@ namespace Discord.Net.Converters writer.WriteValue("online"); break; case UserStatus.Idle: + case UserStatus.AFK: writer.WriteValue("idle"); break; case UserStatus.DoNotDisturb: diff --git a/src/Discord.Net.WebSocket/API/DiscordSocketApiClient.cs b/src/Discord.Net.WebSocket/API/DiscordSocketApiClient.cs index cccda4290..5aea2dcb4 100644 --- a/src/Discord.Net.WebSocket/API/DiscordSocketApiClient.cs +++ b/src/Discord.Net.WebSocket/API/DiscordSocketApiClient.cs @@ -212,12 +212,14 @@ namespace Discord.API options = RequestOptions.CreateOrClone(options); await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false); } - public async Task SendStatusUpdateAsync(long? idleSince, Game game, RequestOptions options = null) + public async Task SendStatusUpdateAsync(UserStatus status, bool isAFK, long? since, Game game, RequestOptions options = null) { options = RequestOptions.CreateOrClone(options); var args = new StatusUpdateParams { - IdleSince = idleSince, + Status = status, + IdleSince = since, + IsAFK = isAFK, Game = game }; await SendGatewayAsync(GatewayOpCode.StatusUpdate, args, options: options).ConfigureAwait(false); diff --git a/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs b/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs index 26b726b36..ae1f79283 100644 --- a/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs +++ b/src/Discord.Net.WebSocket/API/Gateway/StatusUpdateParams.cs @@ -6,8 +6,12 @@ namespace Discord.API.Gateway [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public class StatusUpdateParams { - [JsonProperty("idle_since"), Int53] + [JsonProperty("status")] + public UserStatus Status { get; set; } + [JsonProperty("since"), Int53] public long? IdleSince { get; set; } + [JsonProperty("afk")] + public bool IsAFK { get; set; } [JsonProperty("game")] public Game Game { get; set; } } diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs index 4f3960623..6c59c4b0b 100644 --- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs +++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs @@ -376,7 +376,7 @@ namespace Discord.WebSocket { var user = SocketGlobalUser.Create(this, state, model); user.GlobalUser.AddRef(); - user.Presence = new SocketPresence(null, UserStatus.Online); + user.Presence = new SocketPresence(UserStatus.Online, null); return user; }); } @@ -1311,7 +1311,7 @@ namespace Discord.WebSocket } else { - before = new SocketPresence(null, UserStatus.Offline); + before = new SocketPresence(UserStatus.Offline, null); user = guild.AddOrUpdateUser(data); } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs index 21578de41..926dca5cc 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs @@ -3,6 +3,7 @@ using Discord.Rest; using System; using System.Diagnostics; using System.Threading.Tasks; +using GameEntity = Discord.Game; using Model = Discord.API.User; namespace Discord.WebSocket @@ -10,6 +11,8 @@ namespace Discord.WebSocket [DebuggerDisplay(@"{DebuggerDisplay,nq}")] public class SocketSelfUser : SocketUser, ISelfUser { + private DateTimeOffset? _statusSince; + public string Email { get; private set; } public bool IsVerified { get; private set; } public bool IsMfaEnabled { get; private set; } @@ -44,12 +47,57 @@ namespace Discord.WebSocket IsMfaEnabled = model.MfaEnabled.Value; } - public Task ModifyAsync(Action func) - => UserHelper.ModifyAsync(this, Discord, func); + public Task ModifyAsync(Action func, RequestOptions options = null) + => UserHelper.ModifyAsync(this, Discord, func, options); + public async Task ModifyStatusAsync(Action func, RequestOptions options = null) + { + var args = new ModifyPresenceParams(); + func(args); - internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; + UserStatus status; + if (args.Status.IsSpecified) + { + status = args.Status.Value; + if (status == UserStatus.AFK) + _statusSince = DateTimeOffset.UtcNow; + else + _statusSince = null; + } + else + status = Status; - //ISelfUser - Task ISelfUser.ModifyStatusAsync(Action func) { throw new NotSupportedException(); } + GameEntity? game; + if (args.Game.IsSpecified) + { + var model = args.Game.Value; + if (model != null) + game = GameEntity.Create(model); + else + game = null; + } + else + game = Game; + + Presence = new SocketPresence(status, game); + + await SendStatus(status, game); + } + internal async Task SendStatus(UserStatus status, GameEntity? game) + { + var gameModel = game != null ? new API.Game + { + Name = game.Value.Name, + StreamType = game.Value.StreamType, + StreamUrl = game.Value.StreamUrl + } : null; + + await Discord.ApiClient.SendStatusUpdateAsync( + status, + status == UserStatus.AFK, + _statusSince != null ? _statusSince.Value.ToUnixTimeMilliseconds() : (long?)null, + gameModel); + } + + internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; } } diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketSimpleUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketSimpleUser.cs index a45a68703..1ecb5e578 100644 --- a/src/Discord.Net.WebSocket/Entities/Users/SocketSimpleUser.cs +++ b/src/Discord.Net.WebSocket/Entities/Users/SocketSimpleUser.cs @@ -12,7 +12,7 @@ namespace Discord.WebSocket public override string Username { get; internal set; } public override ushort DiscriminatorValue { get; internal set; } public override string AvatarId { get; internal set; } - internal override SocketPresence Presence { get { return new SocketPresence(null, UserStatus.Offline); } set { } } + internal override SocketPresence Presence { get { return new SocketPresence(UserStatus.Offline, null); } set { } } internal override SocketGlobalUser GlobalUser { get { throw new NotSupportedException(); } }