feature: Send presence on Identify payload (#1688)
* Send presence on identify * Change CurrentUser presence
This commit is contained in:
@@ -15,6 +15,8 @@ namespace Discord.API.Gateway
|
||||
public int LargeThreshold { get; set; }
|
||||
[JsonProperty("shard")]
|
||||
public Optional<int[]> ShardingParams { get; set; }
|
||||
[JsonProperty("presence")]
|
||||
public Optional<StatusUpdateParams> Presence { get; set; }
|
||||
[JsonProperty("guild_subscriptions")]
|
||||
public Optional<bool> GuildSubscriptions { get; set; }
|
||||
[JsonProperty("intents")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CS1591
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Discord.API.Gateway
|
||||
@@ -12,7 +12,7 @@ namespace Discord.API.Gateway
|
||||
public long? IdleSince { get; set; }
|
||||
[JsonProperty("afk")]
|
||||
public bool IsAFK { get; set; }
|
||||
[JsonProperty("game")]
|
||||
public Game Game { get; set; }
|
||||
[JsonProperty("activities")]
|
||||
public Game[] Activities { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GameModel = Discord.API.Game;
|
||||
|
||||
namespace Discord.API
|
||||
{
|
||||
@@ -215,7 +216,7 @@ namespace Discord.API
|
||||
await _sentGatewayMessageEvent.InvokeAsync(opCode).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, int totalShards = 1, bool guildSubscriptions = true, GatewayIntents? gatewayIntents = null, RequestOptions options = null)
|
||||
public async Task SendIdentifyAsync(int largeThreshold = 100, int shardID = 0, int totalShards = 1, bool guildSubscriptions = true, GatewayIntents? gatewayIntents = null, (UserStatus, bool, long?, GameModel[])? presence = null, RequestOptions options = null)
|
||||
{
|
||||
options = RequestOptions.CreateOrClone(options);
|
||||
var props = new Dictionary<string, string>
|
||||
@@ -238,6 +239,17 @@ namespace Discord.API
|
||||
else
|
||||
msg.GuildSubscriptions = guildSubscriptions;
|
||||
|
||||
if (presence.HasValue)
|
||||
{
|
||||
msg.Presence = new StatusUpdateParams
|
||||
{
|
||||
Status = presence.Value.Item1,
|
||||
IsAFK = presence.Value.Item2,
|
||||
IdleSince = presence.Value.Item3,
|
||||
Activities = presence.Value.Item4
|
||||
};
|
||||
}
|
||||
|
||||
await SendGatewayAsync(GatewayOpCode.Identify, msg, options: options).ConfigureAwait(false);
|
||||
}
|
||||
public async Task SendResumeAsync(string sessionId, int lastSeq, RequestOptions options = null)
|
||||
@@ -256,7 +268,7 @@ namespace Discord.API
|
||||
options = RequestOptions.CreateOrClone(options);
|
||||
await SendGatewayAsync(GatewayOpCode.Heartbeat, lastSeq, options: options).ConfigureAwait(false);
|
||||
}
|
||||
public async Task SendStatusUpdateAsync(UserStatus status, bool isAFK, long? since, Game game, RequestOptions options = null)
|
||||
public async Task SendStatusUpdateAsync(UserStatus status, bool isAFK, long? since, GameModel[] game, RequestOptions options = null)
|
||||
{
|
||||
options = RequestOptions.CreateOrClone(options);
|
||||
var args = new StatusUpdateParams
|
||||
@@ -264,7 +276,7 @@ namespace Discord.API
|
||||
Status = status,
|
||||
IdleSince = since,
|
||||
IsAFK = isAFK,
|
||||
Game = game
|
||||
Activities = game
|
||||
};
|
||||
options.BucketId = GatewayBucket.Get(GatewayBucketType.PresenceUpdate).Id;
|
||||
await SendGatewayAsync(GatewayOpCode.StatusUpdate, args, options: options).ConfigureAwait(false);
|
||||
|
||||
@@ -59,7 +59,8 @@ namespace Discord.WebSocket
|
||||
/// <inheritdoc />
|
||||
public override UserStatus Status { get; protected set; } = UserStatus.Online;
|
||||
/// <inheritdoc />
|
||||
public override IActivity Activity { get; protected set; }
|
||||
public override IActivity Activity { get => _activity.GetValueOrDefault(); protected set => _activity = Optional.Create(value); }
|
||||
private Optional<IActivity> _activity;
|
||||
|
||||
//From DiscordSocketConfig
|
||||
internal int TotalShards { get; private set; }
|
||||
@@ -248,14 +249,11 @@ namespace Discord.WebSocket
|
||||
else
|
||||
{
|
||||
await _gatewayLogger.DebugAsync("Identifying").ConfigureAwait(false);
|
||||
await ApiClient.SendIdentifyAsync(shardID: ShardId, totalShards: TotalShards, guildSubscriptions: _guildSubscriptions, gatewayIntents: _gatewayIntents).ConfigureAwait(false);
|
||||
await ApiClient.SendIdentifyAsync(shardID: ShardId, totalShards: TotalShards, guildSubscriptions: _guildSubscriptions, gatewayIntents: _gatewayIntents, presence: BuildCurrentStatus()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//Wait for READY
|
||||
await _connection.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
await _gatewayLogger.DebugAsync("Sending Status").ConfigureAwait(false);
|
||||
await SendStatusAsync().ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -449,28 +447,44 @@ namespace Discord.WebSocket
|
||||
{
|
||||
if (CurrentUser == null)
|
||||
return;
|
||||
CurrentUser.Presence = new SocketPresence(Status, Activity, null, null);
|
||||
|
||||
var presence = BuildCurrentStatus();
|
||||
|
||||
await ApiClient.SendStatusUpdateAsync(
|
||||
presence.Item1,
|
||||
presence.Item2,
|
||||
presence.Item3,
|
||||
presence.Item4).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private (UserStatus, bool, long?, GameModel[]) BuildCurrentStatus()
|
||||
{
|
||||
var status = Status;
|
||||
var statusSince = _statusSince;
|
||||
CurrentUser.Presence = new SocketPresence(status, Activity, null, null);
|
||||
var activity = _activity;
|
||||
|
||||
var gameModel = new GameModel();
|
||||
GameModel[] gameModels = null;
|
||||
// Discord only accepts rich presence over RPC, don't even bother building a payload
|
||||
if (Activity is RichGame)
|
||||
throw new NotSupportedException("Outgoing Rich Presences are not supported via WebSocket.");
|
||||
|
||||
if (Activity != null)
|
||||
if (activity.GetValueOrDefault() != null)
|
||||
{
|
||||
var gameModel = new GameModel();
|
||||
if (activity.Value is RichGame)
|
||||
throw new NotSupportedException("Outgoing Rich Presences are not supported via WebSocket.");
|
||||
gameModel.Name = Activity.Name;
|
||||
gameModel.Type = Activity.Type;
|
||||
if (Activity is StreamingGame streamGame)
|
||||
gameModel.StreamUrl = streamGame.Url;
|
||||
gameModels = new[] { gameModel };
|
||||
}
|
||||
else if (activity.IsSpecified)
|
||||
gameModels = new GameModel[0];
|
||||
|
||||
await ApiClient.SendStatusUpdateAsync(
|
||||
status,
|
||||
status == UserStatus.AFK,
|
||||
statusSince != null ? _statusSince.Value.ToUnixTimeMilliseconds() : (long?)null,
|
||||
gameModel).ConfigureAwait(false);
|
||||
return (status,
|
||||
status == UserStatus.AFK,
|
||||
statusSince != null ? _statusSince.Value.ToUnixTimeMilliseconds() : (long?)null,
|
||||
gameModels);
|
||||
}
|
||||
|
||||
private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string type, object payload)
|
||||
@@ -523,7 +537,7 @@ namespace Discord.WebSocket
|
||||
await _shardedClient.AcquireIdentifyLockAsync(ShardId, _connection.CancelToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await ApiClient.SendIdentifyAsync(shardID: ShardId, totalShards: TotalShards, guildSubscriptions: _guildSubscriptions, gatewayIntents: _gatewayIntents).ConfigureAwait(false);
|
||||
await ApiClient.SendIdentifyAsync(shardID: ShardId, totalShards: TotalShards, guildSubscriptions: _guildSubscriptions, gatewayIntents: _gatewayIntents, presence: BuildCurrentStatus()).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -551,6 +565,7 @@ namespace Discord.WebSocket
|
||||
var state = new ClientState(data.Guilds.Length, data.PrivateChannels.Length);
|
||||
|
||||
var currentUser = SocketSelfUser.Create(this, state, data.User);
|
||||
currentUser.Presence = new SocketPresence(Status, Activity, null, null);
|
||||
ApiClient.CurrentUserId = currentUser.Id;
|
||||
int unavailableGuilds = 0;
|
||||
for (int i = 0; i < data.Guilds.Length; i++)
|
||||
|
||||
Reference in New Issue
Block a user