Added support for more events, added benchmark
This commit is contained in:
@@ -14,8 +14,8 @@ namespace Discord.API
|
|||||||
[JsonProperty("joined_at")]
|
[JsonProperty("joined_at")]
|
||||||
public DateTime?JoinedAt { get; set; }
|
public DateTime?JoinedAt { get; set; }
|
||||||
[JsonProperty("deaf")]
|
[JsonProperty("deaf")]
|
||||||
public bool Deaf { get; set; }
|
public bool? Deaf { get; set; }
|
||||||
[JsonProperty("mute")]
|
[JsonProperty("mute")]
|
||||||
public bool Mute { get; set; }
|
public bool? Mute { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Discord.API
|
|||||||
public Attachment[] Attachments { get; set; }
|
public Attachment[] Attachments { get; set; }
|
||||||
[JsonProperty("embeds")]
|
[JsonProperty("embeds")]
|
||||||
public Embed[] Embeds { get; set; }
|
public Embed[] Embeds { get; set; }
|
||||||
[JsonProperty("nonce")]
|
/*[JsonProperty("nonce")]
|
||||||
public uint? Nonce { get; set; }
|
public object Nonce { get; set; }*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ namespace Discord.API
|
|||||||
{
|
{
|
||||||
[JsonProperty("user")]
|
[JsonProperty("user")]
|
||||||
public User User { get; set; }
|
public User User { get; set; }
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong? GuildId { get; set; }
|
||||||
[JsonProperty("status")]
|
[JsonProperty("status")]
|
||||||
public UserStatus Status { get; set; }
|
public UserStatus Status { get; set; }
|
||||||
[JsonProperty("game")]
|
[JsonProperty("game")]
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ namespace Discord.API
|
|||||||
{
|
{
|
||||||
public class VoiceState
|
public class VoiceState
|
||||||
{
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong? GuildId { get; set; }
|
||||||
[JsonProperty("channel_id")]
|
[JsonProperty("channel_id")]
|
||||||
public ulong ChannelId { get; set; }
|
public ulong? ChannelId { get; set; }
|
||||||
[JsonProperty("user_id")]
|
[JsonProperty("user_id")]
|
||||||
public ulong UserId { get; set; }
|
public ulong UserId { get; set; }
|
||||||
[JsonProperty("session_id")]
|
[JsonProperty("session_id")]
|
||||||
|
|||||||
10
src/Discord.Net/API/Gateway/GuildMemberAddEvent.cs
Normal file
10
src/Discord.Net/API/Gateway/GuildMemberAddEvent.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Gateway
|
||||||
|
{
|
||||||
|
public class GuildMemberAddEvent : GuildMember
|
||||||
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/Discord.Net/API/Gateway/GuildMemberRemoveEvent.cs
Normal file
12
src/Discord.Net/API/Gateway/GuildMemberRemoveEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Gateway
|
||||||
|
{
|
||||||
|
public class GuildMemberRemoveEvent
|
||||||
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
[JsonProperty("user")]
|
||||||
|
public User User { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Discord.Net/API/Gateway/GuildMemberUpdateEvent.cs
Normal file
10
src/Discord.Net/API/Gateway/GuildMemberUpdateEvent.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Discord.API.Gateway
|
||||||
|
{
|
||||||
|
public class GuildMemberUpdateEvent : GuildMember
|
||||||
|
{
|
||||||
|
[JsonProperty("guild_id")]
|
||||||
|
public ulong GuildId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,6 @@ namespace Discord.API.Gateway
|
|||||||
[JsonProperty("guild_id")]
|
[JsonProperty("guild_id")]
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
[JsonProperty("role")]
|
[JsonProperty("role")]
|
||||||
public Role Data { get; set; }
|
public Role Role { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ namespace Discord.API.Gateway
|
|||||||
[JsonProperty("guild_id")]
|
[JsonProperty("guild_id")]
|
||||||
public ulong GuildId { get; set; }
|
public ulong GuildId { get; set; }
|
||||||
[JsonProperty("role")]
|
[JsonProperty("role")]
|
||||||
public Role Data { get; set; }
|
public Role Role { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ namespace Discord
|
|||||||
|
|
||||||
private readonly ConcurrentQueue<ulong> _largeGuilds;
|
private readonly ConcurrentQueue<ulong> _largeGuilds;
|
||||||
private readonly Logger _gatewayLogger;
|
private readonly Logger _gatewayLogger;
|
||||||
|
#if BENCHMARK
|
||||||
|
private readonly Logger _benchmarkLogger;
|
||||||
|
#endif
|
||||||
private readonly DataStoreProvider _dataStoreProvider;
|
private readonly DataStoreProvider _dataStoreProvider;
|
||||||
private readonly JsonSerializer _serializer;
|
private readonly JsonSerializer _serializer;
|
||||||
private readonly int _connectionTimeout, _reconnectDelay, _failedReconnectDelay;
|
private readonly int _connectionTimeout, _reconnectDelay, _failedReconnectDelay;
|
||||||
@@ -106,7 +109,10 @@ namespace Discord
|
|||||||
_largeThreshold = config.LargeThreshold;
|
_largeThreshold = config.LargeThreshold;
|
||||||
|
|
||||||
_gatewayLogger = _log.CreateLogger("Gateway");
|
_gatewayLogger = _log.CreateLogger("Gateway");
|
||||||
|
#if BENCHMARK
|
||||||
|
_benchmarkLogger = _log.CreateLogger("Benchmark");
|
||||||
|
#endif
|
||||||
|
|
||||||
_serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() };
|
_serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() };
|
||||||
|
|
||||||
ApiClient.SentGatewayMessage += async opCode => await _gatewayLogger.Debug($"Sent {(GatewayOpCode)opCode}");
|
ApiClient.SentGatewayMessage += async opCode => await _gatewayLogger.Debug($"Sent {(GatewayOpCode)opCode}");
|
||||||
@@ -207,7 +213,7 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
dataStore = dataStore ?? DataStore;
|
dataStore = dataStore ?? DataStore;
|
||||||
|
|
||||||
var guild = new CachedGuild(this, model);
|
var guild = new CachedGuild(this, model, dataStore);
|
||||||
if (model.Unavailable != true)
|
if (model.Unavailable != true)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < model.Channels.Length; i++)
|
for (int i = 0; i < model.Channels.Length; i++)
|
||||||
@@ -247,7 +253,7 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
dataStore = dataStore ?? DataStore;
|
dataStore = dataStore ?? DataStore;
|
||||||
|
|
||||||
var recipient = AddCachedUser(model.Recipient, dataStore);
|
var recipient = GetOrAddCachedUser(model.Recipient, dataStore);
|
||||||
var channel = recipient.AddDMChannel(model);
|
var channel = recipient.AddDMChannel(model);
|
||||||
dataStore.AddChannel(channel);
|
dataStore.AddChannel(channel);
|
||||||
return channel;
|
return channel;
|
||||||
@@ -287,7 +293,7 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
return Task.FromResult<IUser>(DataStore.Users.Where(x => x.Discriminator == discriminator && x.Username == username).FirstOrDefault());
|
return Task.FromResult<IUser>(DataStore.Users.Where(x => x.Discriminator == discriminator && x.Username == username).FirstOrDefault());
|
||||||
}
|
}
|
||||||
internal CachedPublicUser AddCachedUser(API.User model, DataStore dataStore = null)
|
internal CachedPublicUser GetOrAddCachedUser(API.User model, DataStore dataStore = null)
|
||||||
{
|
{
|
||||||
dataStore = dataStore ?? DataStore;
|
dataStore = dataStore ?? DataStore;
|
||||||
|
|
||||||
@@ -299,8 +305,7 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
dataStore = dataStore ?? DataStore;
|
dataStore = dataStore ?? DataStore;
|
||||||
|
|
||||||
var user = dataStore.GetUser(id);
|
var user = dataStore.RemoveUser(id);
|
||||||
user.RemoveRef();
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +341,7 @@ namespace Discord
|
|||||||
batchTasks[j] = guild.DownloaderPromise;
|
batchTasks[j] = guild.DownloaderPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiClient.SendRequestMembers(batchIds);
|
await ApiClient.SendRequestMembers(batchIds).ConfigureAwait(false);
|
||||||
|
|
||||||
if (isLast && batchCount > 1)
|
if (isLast && batchCount > 1)
|
||||||
await Task.WhenAll(batchTasks.Take(count)).ConfigureAwait(false);
|
await Task.WhenAll(batchTasks.Take(count)).ConfigureAwait(false);
|
||||||
@@ -347,474 +352,511 @@ namespace Discord
|
|||||||
|
|
||||||
private async Task ProcessMessage(GatewayOpCode opCode, int? seq, string type, object payload)
|
private async Task ProcessMessage(GatewayOpCode opCode, int? seq, string type, object payload)
|
||||||
{
|
{
|
||||||
if (seq != null)
|
#if BENCHMARK
|
||||||
_lastSeq = seq.Value;
|
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (opCode)
|
#endif
|
||||||
|
if (seq != null)
|
||||||
|
_lastSeq = seq.Value;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
case GatewayOpCode.Hello:
|
switch (opCode)
|
||||||
{
|
{
|
||||||
var data = (payload as JToken).ToObject<HelloEvent>(_serializer);
|
case GatewayOpCode.Hello:
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Hello").ConfigureAwait(false);
|
||||||
|
var data = (payload as JToken).ToObject<HelloEvent>(_serializer);
|
||||||
|
|
||||||
await ApiClient.SendIdentify().ConfigureAwait(false);
|
await ApiClient.SendIdentify().ConfigureAwait(false);
|
||||||
_heartbeatTask = RunHeartbeat(data.HeartbeatInterval, _heartbeatCancelToken.Token);
|
_heartbeatTask = RunHeartbeat(data.HeartbeatInterval, _heartbeatCancelToken.Token);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GatewayOpCode.HeartbeatAck:
|
case GatewayOpCode.HeartbeatAck:
|
||||||
{
|
{
|
||||||
var latency = (int)(Environment.TickCount - _heartbeatTime);
|
await _gatewayLogger.Debug($"Received HeartbeatAck").ConfigureAwait(false);
|
||||||
await _gatewayLogger.Debug($"Latency: {latency} ms").ConfigureAwait(false);
|
|
||||||
Latency = latency;
|
|
||||||
|
|
||||||
await LatencyUpdated.Raise(latency).ConfigureAwait(false);
|
var latency = (int)(Environment.TickCount - _heartbeatTime);
|
||||||
}
|
await _gatewayLogger.Debug($"Latency = {latency} ms").ConfigureAwait(false);
|
||||||
break;
|
Latency = latency;
|
||||||
case GatewayOpCode.Dispatch:
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
//Global
|
|
||||||
case "READY":
|
|
||||||
{
|
|
||||||
//TODO: Make downloading large guilds optional
|
|
||||||
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer);
|
|
||||||
var dataStore = _dataStoreProvider(ShardId, _totalShards, data.Guilds.Length, data.PrivateChannels.Length);
|
|
||||||
|
|
||||||
_currentUser = new CachedSelfUser(this, data.User);
|
await LatencyUpdated.Raise(latency).ConfigureAwait(false);
|
||||||
|
}
|
||||||
for (int i = 0; i < data.Guilds.Length; i++)
|
break;
|
||||||
AddCachedGuild(data.Guilds[i], dataStore);
|
case GatewayOpCode.Dispatch:
|
||||||
for (int i = 0; i < data.PrivateChannels.Length; i++)
|
switch (type)
|
||||||
AddCachedDMChannel(data.PrivateChannels[i], dataStore);
|
{
|
||||||
|
//Global
|
||||||
_sessionId = data.SessionId;
|
case "READY":
|
||||||
DataStore = dataStore;
|
|
||||||
|
|
||||||
await Ready.Raise().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_connectTask.TrySetResult(true); //Signal the .Connect() call to complete
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Guilds
|
|
||||||
case "GUILD_CREATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
|
||||||
var guild = new CachedGuild(this, data);
|
|
||||||
DataStore.AddGuild(guild);
|
|
||||||
|
|
||||||
if (data.Unavailable == false)
|
|
||||||
type = "GUILD_AVAILABLE";
|
|
||||||
else
|
|
||||||
await JoinedGuild.Raise(guild).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await GuildAvailable.Raise(guild);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Guild>(_serializer);
|
|
||||||
var guild = DataStore.GetGuild(data.Id);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
{
|
||||||
var before = _enablePreUpdateEvents ? guild.Clone() : null;
|
await _gatewayLogger.Debug($"Received Dispatch (READY)").ConfigureAwait(false);
|
||||||
guild.Update(data, UpdateSource.WebSocket);
|
|
||||||
await GuildUpdated.Raise(before, guild);
|
//TODO: Make downloading large guilds optional
|
||||||
|
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer);
|
||||||
|
var dataStore = _dataStoreProvider(ShardId, _totalShards, data.Guilds.Length, data.PrivateChannels.Length);
|
||||||
|
|
||||||
|
_currentUser = new CachedSelfUser(this, data.User);
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Guilds.Length; i++)
|
||||||
|
AddCachedGuild(data.Guilds[i], dataStore);
|
||||||
|
for (int i = 0; i < data.PrivateChannels.Length; i++)
|
||||||
|
AddCachedDMChannel(data.PrivateChannels[i], dataStore);
|
||||||
|
|
||||||
|
_sessionId = data.SessionId;
|
||||||
|
DataStore = dataStore;
|
||||||
|
|
||||||
|
await Ready.Raise().ConfigureAwait(false);
|
||||||
|
|
||||||
|
_connectTask.TrySetResult(true); //Signal the .Connect() call to complete
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("GUILD_UPDATE referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_DELETE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
|
||||||
var guild = DataStore.RemoveGuild(data.Id);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
|
||||||
if (data.Unavailable == true)
|
|
||||||
type = "GUILD_UNAVAILABLE";
|
|
||||||
|
|
||||||
await GuildUnavailable.Raise(guild);
|
//Guilds
|
||||||
if (data.Unavailable != true)
|
case "GUILD_CREATE":
|
||||||
await LeftGuild.Raise(guild);
|
{
|
||||||
|
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
||||||
|
var guild = new CachedGuild(this, data, DataStore);
|
||||||
|
DataStore.AddGuild(guild);
|
||||||
|
|
||||||
|
if (data.Unavailable == false)
|
||||||
|
type = "GUILD_AVAILABLE";
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch ({type})").ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (data.Unavailable != false)
|
||||||
|
await JoinedGuild.Raise(guild).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await GuildAvailable.Raise(guild).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("GUILD_DELETE referenced an unknown guild.");
|
case "GUILD_UPDATE":
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Channels
|
|
||||||
case "CHANNEL_CREATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
|
||||||
|
|
||||||
ICachedChannel channel = null;
|
|
||||||
if (data.GuildId != null)
|
|
||||||
{
|
{
|
||||||
var guild = DataStore.GetGuild(data.GuildId.Value);
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_UPDATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<API.Guild>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.Id);
|
||||||
if (guild != null)
|
if (guild != null)
|
||||||
{
|
{
|
||||||
channel = guild.AddCachedChannel(data);
|
var before = _enablePreUpdateEvents ? guild.Clone() : null;
|
||||||
DataStore.AddChannel(channel);
|
guild.Update(data, UpdateSource.WebSocket);
|
||||||
|
await GuildUpdated.Raise(before, guild).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await _gatewayLogger.Warning("CHANNEL_CREATE referenced an unknown guild.");
|
await _gatewayLogger.Warning("GUILD_UPDATE referenced an unknown guild.");
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
channel = AddCachedDMChannel(data);
|
case "GUILD_DELETE":
|
||||||
if (channel != null)
|
|
||||||
await ChannelCreated.Raise(channel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "CHANNEL_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
|
||||||
var channel = DataStore.GetChannel(data.Id);
|
|
||||||
if (channel != null)
|
|
||||||
{
|
{
|
||||||
var before = _enablePreUpdateEvents ? channel.Clone() : null;
|
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
||||||
channel.Update(data, UpdateSource.WebSocket);
|
if (data.Unavailable == true)
|
||||||
await ChannelUpdated.Raise(before, channel);
|
type = "GUILD_UNAVAILABLE";
|
||||||
}
|
await _gatewayLogger.Debug($"Received Dispatch ({type})").ConfigureAwait(false);
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("CHANNEL_UPDATE referenced an unknown channel.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "CHANNEL_DELETE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
|
||||||
var channel = RemoveCachedChannel(data.Id);
|
|
||||||
if (channel != null)
|
|
||||||
await ChannelDestroyed.Raise(channel);
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("CHANNEL_DELETE referenced an unknown channel.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Members
|
var guild = DataStore.RemoveGuild(data.Id);
|
||||||
/*case "GUILD_MEMBER_ADD":
|
if (guild != null)
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.GuildMember>(_serializer);
|
|
||||||
var guild = GetGuild(data.GuildId.Value);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
|
||||||
var user = guild.AddCachedUser(data.User.Id, true, true);
|
|
||||||
user.Update(data);
|
|
||||||
user.UpdateActivity();
|
|
||||||
UserJoined.Raise(user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("GUILD_MEMBER_ADD referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_MEMBER_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.GuildMember>(_serializer);
|
|
||||||
var guild = GetGuild(data.GuildId.Value);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
|
||||||
var user = guild.GetCachedUser(data.User.Id);
|
|
||||||
if (user != null)
|
|
||||||
{
|
{
|
||||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
await GuildUnavailable.Raise(guild).ConfigureAwait(false);
|
||||||
user.Update(data);
|
if (data.Unavailable != true)
|
||||||
await UserUpdated.Raise(before, user);
|
await LeftGuild.Raise(guild).ConfigureAwait(false);
|
||||||
|
foreach (var member in guild.Members)
|
||||||
|
member.User.RemoveRef();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown user.");
|
await _gatewayLogger.Warning($"{type} referenced an unknown guild.").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown guild.");
|
|
||||||
}
|
//Channels
|
||||||
break;
|
case "CHANNEL_CREATE":
|
||||||
case "GUILD_MEMBER_REMOVE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.GuildMember>(_serializer);
|
|
||||||
var guild = GetGuild(data.GuildId.Value);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
{
|
||||||
var user = guild.RemoveCachedUser(data.User.Id);
|
await _gatewayLogger.Debug($"Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false);
|
||||||
if (user != null)
|
|
||||||
|
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||||
|
ICachedChannel channel = null;
|
||||||
|
if (data.GuildId != null)
|
||||||
{
|
{
|
||||||
user.GlobalUser.RemoveGuild();
|
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||||
if (user.GuildCount == 0 && user.DMChannel == null)
|
if (guild != null)
|
||||||
DataStore.RemoveUser(user.Id);
|
{
|
||||||
await UserLeft.Raise(user);
|
channel = guild.AddCachedChannel(data);
|
||||||
|
DataStore.AddChannel(channel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("CHANNEL_CREATE referenced an unknown guild.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown user.");
|
channel = AddCachedDMChannel(data);
|
||||||
|
if (channel != null)
|
||||||
|
await ChannelCreated.Raise(channel);
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown guild.");
|
case "CHANNEL_UPDATE":
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_MEMBERS_CHUNK":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<GuildMembersChunkEvent>(_serializer);
|
|
||||||
var guild = GetCachedGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
{
|
||||||
foreach (var memberData in data.Members)
|
await _gatewayLogger.Debug($"Received Dispatch (CHANNEL_UPDATE)").ConfigureAwait(false);
|
||||||
{
|
|
||||||
var user = guild.AddCachedUser(memberData.User.Id, true, false);
|
|
||||||
user.Update(memberData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (guild.CurrentUserCount >= guild.UserCount) //Finished downloading for there
|
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||||
await GuildAvailable.Raise(guild);
|
var channel = DataStore.GetChannel(data.Id);
|
||||||
}
|
if (channel != null)
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("GUILD_MEMBERS_CHUNK referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Roles
|
|
||||||
/*case "GUILD_ROLE_CREATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<GuildRoleCreateEvent>(_serializer);
|
|
||||||
var guild = GetCachedGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
|
||||||
var role = guild.AddCachedRole(data.Data.Id);
|
|
||||||
role.Update(data.Data, false);
|
|
||||||
RoleCreated.Raise(role);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("GUILD_ROLE_CREATE referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_ROLE_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<GuildRoleUpdateEvent>(_serializer);
|
|
||||||
var guild = GetCachedGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
|
||||||
var role = guild.GetRole(data.Data.Id);
|
|
||||||
if (role != null)
|
|
||||||
{
|
{
|
||||||
var before = _enablePreUpdateEvents ? role.Clone() : null;
|
var before = _enablePreUpdateEvents ? channel.Clone() : null;
|
||||||
role.Update(data.Data, true);
|
channel.Update(data, UpdateSource.WebSocket);
|
||||||
RoleUpdated.Raise(before, role);
|
await ChannelUpdated.Raise(before, channel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown role.");
|
await _gatewayLogger.Warning("CHANNEL_UPDATE referenced an unknown channel.");
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown guild.");
|
case "CHANNEL_DELETE":
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_ROLE_DELETE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<GuildRoleDeleteEvent>(_serializer);
|
|
||||||
var guild = DataStore.GetGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
{
|
||||||
var role = guild.RemoveRole(data.RoleId);
|
await _gatewayLogger.Debug($"Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false);
|
||||||
if (role != null)
|
|
||||||
RoleDeleted.Raise(role);
|
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||||
|
var channel = RemoveCachedChannel(data.Id);
|
||||||
|
if (channel != null)
|
||||||
|
await ChannelDestroyed.Raise(channel);
|
||||||
else
|
else
|
||||||
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown role.");
|
await _gatewayLogger.Warning("CHANNEL_DELETE referenced an unknown channel.");
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Bans
|
//Members
|
||||||
case "GUILD_BAN_ADD":
|
case "GUILD_MEMBER_ADD":
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<GuildBanEvent>(_serializer);
|
|
||||||
var guild = GetCachedGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
await UserBanned.Raise(new User(this, data));
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("GUILD_BAN_ADD referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "GUILD_BAN_REMOVE":
|
|
||||||
{
|
|
||||||
var data = payload.ToObject<GuildBanEvent>(_serializer);
|
|
||||||
var guild = GetCachedGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
await UserUnbanned.Raise(new User(this, data));
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("GUILD_BAN_REMOVE referenced an unknown guild.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Messages
|
|
||||||
case "MESSAGE_CREATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
|
||||||
var channel = DataStore.GetChannel(data.ChannelId);
|
|
||||||
if (channel != null)
|
|
||||||
{
|
{
|
||||||
var user = channel.GetUser(data.Author.Id);
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false);
|
||||||
|
|
||||||
if (user != null)
|
var data = (payload as JToken).ToObject<GuildMemberAddEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
{
|
{
|
||||||
bool isAuthor = data.Author.Id == CurrentUser.Id;
|
var user = guild.AddCachedUser(data);
|
||||||
var msg = channel.AddMessage(data.Id, user, data.Timestamp.Value);
|
await UserJoined.Raise(user).ConfigureAwait(false);
|
||||||
|
|
||||||
msg.Update(data);
|
|
||||||
|
|
||||||
MessageReceived.Raise(msg);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown user.");
|
await _gatewayLogger.Warning("GUILD_MEMBER_ADD referenced an unknown guild.");
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown channel.");
|
case "GUILD_MEMBER_UPDATE":
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "MESSAGE_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
|
||||||
var channel = GetCachedChannel(data.ChannelId);
|
|
||||||
if (channel != null)
|
|
||||||
{
|
{
|
||||||
var msg = channel.GetMessage(data.Id, data.Author?.Id);
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBER_UPDATE)").ConfigureAwait(false);
|
||||||
var before = _enablePreUpdateEvents ? msg.Clone() : null;
|
|
||||||
msg.Update(data);
|
|
||||||
MessageUpdated.Raise(before, msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("MESSAGE_UPDATE referenced an unknown channel.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "MESSAGE_DELETE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
|
||||||
var channel = GetCachedChannel(data.ChannelId);
|
|
||||||
if (channel != null)
|
|
||||||
{
|
|
||||||
var msg = channel.RemoveMessage(data.Id);
|
|
||||||
MessageDeleted.Raise(msg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
await _gatewayLogger.Warning("MESSAGE_DELETE referenced an unknown channel.");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Statuses
|
var data = (payload as JToken).ToObject<GuildMemberUpdateEvent>(_serializer);
|
||||||
case "PRESENCE_UPDATE":
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
{
|
if (guild != null)
|
||||||
var data = (payload as JToken).ToObject<API.Presence>(_serializer);
|
|
||||||
User user;
|
|
||||||
Guild guild;
|
|
||||||
if (data.GuildId == null)
|
|
||||||
{
|
|
||||||
guild = null;
|
|
||||||
user = GetPrivateChannel(data.User.Id)?.Recipient;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
guild = GetGuild(data.GuildId.Value);
|
|
||||||
if (guild == null)
|
|
||||||
{
|
{
|
||||||
await _gatewayLogger.Warning("PRESENCE_UPDATE referenced an unknown guild.");
|
var user = guild.GetCachedUser(data.User.Id);
|
||||||
break;
|
if (user != null)
|
||||||
|
{
|
||||||
|
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
||||||
|
user.Update(data, UpdateSource.WebSocket);
|
||||||
|
await UserUpdated.Raise(before, user);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown user.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
user = guild.GetUser(data.User.Id);
|
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown guild.");
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "GUILD_MEMBER_REMOVE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBER_REMOVE)").ConfigureAwait(false);
|
||||||
|
|
||||||
if (user != null)
|
var data = (payload as JToken).ToObject<GuildMemberRemoveEvent>(_serializer);
|
||||||
{
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
if (guild != null)
|
||||||
user.Update(data);
|
|
||||||
UserUpdated.Raise(before, user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Occurs when a user leaves a guild
|
|
||||||
//await _gatewayLogger.Warning("PRESENCE_UPDATE referenced an unknown user.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "TYPING_START":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer);
|
|
||||||
var channel = GetCachedChannel(data.ChannelId);
|
|
||||||
if (channel != null)
|
|
||||||
{
|
|
||||||
var user = channel.GetUser(data.UserId);
|
|
||||||
if (user != null)
|
|
||||||
{
|
{
|
||||||
await UserIsTyping.Raise(channel, user);
|
var user = guild.RemoveCachedUser(data.User.Id);
|
||||||
user.UpdateActivity();
|
if (user != null)
|
||||||
|
{
|
||||||
|
user.User.RemoveRef();
|
||||||
|
await UserLeft.Raise(user);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown user.");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown guild.");
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("TYPING_START referenced an unknown channel.");
|
case "GUILD_MEMBERS_CHUNK":
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Voice
|
|
||||||
case "VOICE_STATE_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<API.VoiceState>(_serializer);
|
|
||||||
var guild = GetGuild(data.GuildId);
|
|
||||||
if (guild != null)
|
|
||||||
{
|
{
|
||||||
var user = guild.GetUser(data.UserId);
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBERS_CHUNK)").ConfigureAwait(false);
|
||||||
if (user != null)
|
|
||||||
|
var data = (payload as JToken).ToObject<GuildMembersChunkEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
{
|
{
|
||||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
foreach (var memberModel in data.Members)
|
||||||
user.Update(data);
|
guild.AddCachedUser(memberModel);
|
||||||
UserUpdated.Raise(before, user);
|
|
||||||
|
if (guild.DownloadedMemberCount >= guild.MemberCount) //Finished downloading for there
|
||||||
|
{
|
||||||
|
guild.CompleteDownloadMembers();
|
||||||
|
await GuildDownloadedMembers.Raise(guild).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_MEMBERS_CHUNK referenced an unknown guild.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Roles
|
||||||
|
case "GUILD_ROLE_CREATE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<GuildRoleCreateEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
|
{
|
||||||
|
var role = guild.AddCachedRole(data.Role);
|
||||||
|
await RoleCreated.Raise(role).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_ROLE_CREATE referenced an unknown guild.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "GUILD_ROLE_UPDATE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_ROLE_UPDATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<GuildRoleUpdateEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
|
{
|
||||||
|
var role = guild.GetRole(data.Role.Id);
|
||||||
|
if (role != null)
|
||||||
|
{
|
||||||
|
var before = _enablePreUpdateEvents ? role.Clone() : null;
|
||||||
|
role.Update(data.Role, UpdateSource.WebSocket);
|
||||||
|
await RoleUpdated.Raise(before, role).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown role.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown guild.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "GUILD_ROLE_DELETE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_ROLE_DELETE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<GuildRoleDeleteEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
|
{
|
||||||
|
var role = guild.RemoveCachedRole(data.RoleId);
|
||||||
|
if (role != null)
|
||||||
|
await RoleDeleted.Raise(role).ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown role.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown guild.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Bans
|
||||||
|
case "GUILD_BAN_ADD":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<GuildBanEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
|
await UserBanned.Raise(new User(this, data));
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_BAN_ADD referenced an unknown guild.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "GUILD_BAN_REMOVE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (GUILD_BAN_REMOVE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<GuildBanEvent>(_serializer);
|
||||||
|
var guild = DataStore.GetGuild(data.GuildId);
|
||||||
|
if (guild != null)
|
||||||
|
await UserUnbanned.Raise(new User(this, data));
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("GUILD_BAN_REMOVE referenced an unknown guild.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Messages
|
||||||
|
case "MESSAGE_CREATE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||||
|
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
var author = channel.GetCachedUser(data.Author.Id);
|
||||||
|
|
||||||
|
if (author != null)
|
||||||
|
{
|
||||||
|
var msg = channel.AddCachedMessage(author, data);
|
||||||
|
await MessageReceived.Raise(msg).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown user.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown channel.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "MESSAGE_UPDATE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||||
|
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
var msg = channel.GetCachedMessage(data.Id);
|
||||||
|
var before = _enablePreUpdateEvents ? msg.Clone() : null;
|
||||||
|
msg.Update(data, UpdateSource.WebSocket);
|
||||||
|
await MessageUpdated.Raise(before, msg).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("MESSAGE_UPDATE referenced an unknown channel.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "MESSAGE_DELETE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||||
|
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
var msg = channel.RemoveCachedMessage(data.Id);
|
||||||
|
await MessageDeleted.Raise(msg).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("MESSAGE_DELETE referenced an unknown channel.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Statuses
|
||||||
|
case "PRESENCE_UPDATE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<API.Presence>(_serializer);
|
||||||
|
if (data.GuildId == null)
|
||||||
|
{
|
||||||
|
var user = DataStore.GetUser(data.User.Id);
|
||||||
|
if (user == null)
|
||||||
|
user.Update(data, UpdateSource.WebSocket);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Occurs when a user leaves a guild
|
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||||
//await _gatewayLogger.Warning("VOICE_STATE_UPDATE referenced an unknown user.");
|
if (guild == null)
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Warning("PRESENCE_UPDATE referenced an unknown guild.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (data.Status == UserStatus.Offline)
|
||||||
|
guild.RemoveCachedPresence(data.User.Id);
|
||||||
|
else
|
||||||
|
guild.AddOrUpdateCachedPresence(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
break;
|
||||||
await _gatewayLogger.Warning("VOICE_STATE_UPDATE referenced an unknown guild.");
|
case "TYPING_START":
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Settings
|
|
||||||
case "USER_UPDATE":
|
|
||||||
{
|
|
||||||
var data = (payload as JToken).ToObject<SelfUser>(_serializer);
|
|
||||||
if (data.Id == CurrentUser.Id)
|
|
||||||
{
|
{
|
||||||
var before = _enablePreUpdateEvents ? CurrentUser.Clone() : null;
|
await _gatewayLogger.Debug($"Received Dispatch (TYPING_START)").ConfigureAwait(false);
|
||||||
CurrentUser.Update(data);
|
|
||||||
await CurrentUserUpdated.Raise(before, CurrentUser).ConfigureAwait(false);
|
var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer);
|
||||||
|
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||||
|
if (channel != null)
|
||||||
|
{
|
||||||
|
var user = channel.GetCachedUser(data.UserId);
|
||||||
|
if (user != null)
|
||||||
|
await UserIsTyping.Raise(channel, user).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("TYPING_START referenced an unknown channel.").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;*/
|
|
||||||
|
|
||||||
//Ignored
|
//Voice
|
||||||
case "USER_SETTINGS_UPDATE":
|
case "VOICE_STATE_UPDATE":
|
||||||
case "MESSAGE_ACK": //TODO: Add (User only)
|
{
|
||||||
case "GUILD_EMOJIS_UPDATE": //TODO: Add
|
await _gatewayLogger.Debug($"Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false);
|
||||||
case "GUILD_INTEGRATIONS_UPDATE": //TODO: Add
|
|
||||||
case "VOICE_SERVER_UPDATE": //TODO: Add
|
|
||||||
case "RESUMED": //TODO: Add
|
|
||||||
await _gatewayLogger.Debug($"Ignored Dispatch ({type})").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
|
|
||||||
//Others
|
var data = (payload as JToken).ToObject<API.VoiceState>(_serializer);
|
||||||
default:
|
if (data.GuildId.HasValue)
|
||||||
await _gatewayLogger.Warning($"Unknown Dispatch ({type})").ConfigureAwait(false);
|
{
|
||||||
return;
|
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||||
}
|
if (guild != null)
|
||||||
break;
|
{
|
||||||
default:
|
if (data.ChannelId == null)
|
||||||
await _gatewayLogger.Warning($"Unknown OpCode ({opCode})").ConfigureAwait(false);
|
guild.RemoveCachedVoiceState(data.UserId);
|
||||||
return;
|
else
|
||||||
|
guild.AddOrUpdateCachedVoiceState(data);
|
||||||
|
|
||||||
|
var user = guild.GetCachedUser(data.UserId);
|
||||||
|
user.Update(data, UpdateSource.WebSocket);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
await _gatewayLogger.Warning("VOICE_STATE_UPDATE referenced an unknown guild.").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
case "USER_UPDATE":
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Debug($"Received Dispatch (USER_UPDATE)").ConfigureAwait(false);
|
||||||
|
|
||||||
|
var data = (payload as JToken).ToObject<API.User>(_serializer);
|
||||||
|
if (data.Id == CurrentUser.Id)
|
||||||
|
{
|
||||||
|
var before = _enablePreUpdateEvents ? CurrentUser.Clone() : null;
|
||||||
|
CurrentUser.Update(data, UpdateSource.WebSocket);
|
||||||
|
await CurrentUserUpdated.Raise(before, CurrentUser).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Ignored
|
||||||
|
case "USER_SETTINGS_UPDATE":
|
||||||
|
case "MESSAGE_ACK": //TODO: Add (User only)
|
||||||
|
case "GUILD_EMOJIS_UPDATE": //TODO: Add
|
||||||
|
case "GUILD_INTEGRATIONS_UPDATE": //TODO: Add
|
||||||
|
case "VOICE_SERVER_UPDATE": //TODO: Add
|
||||||
|
case "RESUMED": //TODO: Add
|
||||||
|
await _gatewayLogger.Debug($"Ignored Dispatch ({type})").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Others
|
||||||
|
default:
|
||||||
|
await _gatewayLogger.Warning($"Unknown Dispatch ({type})").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await _gatewayLogger.Warning($"Unknown OpCode ({opCode})").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await _gatewayLogger.Error($"Error handling {opCode}{(type != null ? $" ({type})" : "")}", ex).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if BENCHMARK
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
finally
|
||||||
{
|
{
|
||||||
await _gatewayLogger.Error($"Error handling {opCode}{(type != null ? $" ({type})" : "")}", ex).ConfigureAwait(false);
|
stopwatch.Stop();
|
||||||
return;
|
double millis = Math.Round(stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2);
|
||||||
|
await _benchmarkLogger.Debug($"{millis} ms").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await _gatewayLogger.Debug($"Received {opCode}{(type != null ? $" ({type})" : "")}").ConfigureAwait(false);
|
#endif
|
||||||
}
|
}
|
||||||
private async Task RunHeartbeat(int intervalMillis, CancellationToken cancelToken)
|
private async Task RunHeartbeat(int intervalMillis, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
await Discord.ApiClient.DeleteGuildRole(Guild.Id, Id).ConfigureAwait(false);
|
await Discord.ApiClient.DeleteGuildRole(Guild.Id, Id).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Role Clone() => MemberwiseClone() as Role;
|
||||||
|
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
private string DebuggerDisplay => $"{Name} ({Id})";
|
private string DebuggerDisplay => $"{Name} ({Id})";
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Collections.Immutable;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Model = Discord.API.GuildMember;
|
using Model = Discord.API.GuildMember;
|
||||||
|
using VoiceStateModel = Discord.API.VoiceState;
|
||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
@@ -24,12 +25,12 @@ namespace Discord
|
|||||||
public string AvatarUrl => User.AvatarUrl;
|
public string AvatarUrl => User.AvatarUrl;
|
||||||
public DateTime CreatedAt => User.CreatedAt;
|
public DateTime CreatedAt => User.CreatedAt;
|
||||||
public string Discriminator => User.Discriminator;
|
public string Discriminator => User.Discriminator;
|
||||||
public Game? Game => User.Game;
|
|
||||||
public bool IsAttached => User.IsAttached;
|
public bool IsAttached => User.IsAttached;
|
||||||
public bool IsBot => User.IsBot;
|
public bool IsBot => User.IsBot;
|
||||||
public string Mention => User.Mention;
|
public string Mention => User.Mention;
|
||||||
public UserStatus Status => User.Status;
|
|
||||||
public string Username => User.Username;
|
public string Username => User.Username;
|
||||||
|
public virtual UserStatus Status => User.Status;
|
||||||
|
public virtual Game? Game => User.Game;
|
||||||
|
|
||||||
public DiscordClient Discord => Guild.Discord;
|
public DiscordClient Discord => Guild.Discord;
|
||||||
|
|
||||||
@@ -43,8 +44,10 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
if (source == UpdateSource.Rest && IsAttached) return;
|
if (source == UpdateSource.Rest && IsAttached) return;
|
||||||
|
|
||||||
IsDeaf = model.Deaf;
|
if (model.Deaf.HasValue)
|
||||||
IsMute = model.Mute;
|
IsDeaf = model.Deaf.Value;
|
||||||
|
if (model.Mute.HasValue)
|
||||||
|
IsMute = model.Mute.Value;
|
||||||
JoinedAt = model.JoinedAt.Value;
|
JoinedAt = model.JoinedAt.Value;
|
||||||
Nickname = model.Nick;
|
Nickname = model.Nick;
|
||||||
|
|
||||||
@@ -56,6 +59,13 @@ namespace Discord
|
|||||||
|
|
||||||
GuildPermissions = new GuildPermissions(Permissions.ResolveGuild(this));
|
GuildPermissions = new GuildPermissions(Permissions.ResolveGuild(this));
|
||||||
}
|
}
|
||||||
|
public void Update(VoiceStateModel model, UpdateSource source)
|
||||||
|
{
|
||||||
|
if (source == UpdateSource.Rest && IsAttached) return;
|
||||||
|
|
||||||
|
IsDeaf = model.Deaf;
|
||||||
|
IsMute = model.Mute;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Update()
|
public async Task Update()
|
||||||
{
|
{
|
||||||
@@ -107,6 +117,10 @@ namespace Discord
|
|||||||
|
|
||||||
IGuild IGuildUser.Guild => Guild;
|
IGuild IGuildUser.Guild => Guild;
|
||||||
IReadOnlyCollection<IRole> IGuildUser.Roles => Roles;
|
IReadOnlyCollection<IRole> IGuildUser.Roles => Roles;
|
||||||
IVoiceChannel IGuildUser.VoiceChannel => null;
|
bool IVoiceState.IsSelfDeafened => false;
|
||||||
|
bool IVoiceState.IsSelfMuted => false;
|
||||||
|
bool IVoiceState.IsSuppressed => false;
|
||||||
|
IVoiceChannel IVoiceState.VoiceChannel => null;
|
||||||
|
string IVoiceState.VoiceSessionId => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using Discord.API.Rest;
|
|||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
/// <summary> A Guild-User pairing. </summary>
|
/// <summary> A Guild-User pairing. </summary>
|
||||||
public interface IGuildUser : IUpdateable, IUser
|
public interface IGuildUser : IUpdateable, IUser, IVoiceState
|
||||||
{
|
{
|
||||||
/// <summary> Returns true if the guild has deafened this user. </summary>
|
/// <summary> Returns true if the guild has deafened this user. </summary>
|
||||||
bool IsDeaf { get; }
|
bool IsDeaf { get; }
|
||||||
@@ -23,8 +23,6 @@ namespace Discord
|
|||||||
IGuild Guild { get; }
|
IGuild Guild { get; }
|
||||||
/// <summary> Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. </summary>
|
/// <summary> Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. </summary>
|
||||||
IReadOnlyCollection<IRole> Roles { get; }
|
IReadOnlyCollection<IRole> Roles { get; }
|
||||||
/// <summary> Gets the voice channel this user is currently in, if any. </summary>
|
|
||||||
IVoiceChannel VoiceChannel { get; }
|
|
||||||
|
|
||||||
/// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary>
|
/// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary>
|
||||||
ChannelPermissions GetPermissions(IGuildChannel channel);
|
ChannelPermissions GetPermissions(IGuildChannel channel);
|
||||||
|
|||||||
16
src/Discord.Net/Entities/Users/IVoiceState.cs
Normal file
16
src/Discord.Net/Entities/Users/IVoiceState.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Discord
|
||||||
|
{
|
||||||
|
public interface IVoiceState
|
||||||
|
{
|
||||||
|
/// <summary> Returns true if this user has marked themselves as deafened. </summary>
|
||||||
|
bool IsSelfDeafened { get; }
|
||||||
|
/// <summary> Returns true if this user has marked themselves as muted. </summary>
|
||||||
|
bool IsSelfMuted { get; }
|
||||||
|
/// <summary> Returns true if the guild is temporarily blocking audio to/from this user. </summary>
|
||||||
|
bool IsSuppressed { get; }
|
||||||
|
/// <summary> Gets the voice channel this user is currently in, if any. </summary>
|
||||||
|
IVoiceChannel VoiceChannel { get; }
|
||||||
|
/// <summary> Gets the unique identifier for this user's voice session. </summary>
|
||||||
|
string VoiceSessionId { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ namespace Discord
|
|||||||
|
|
||||||
var model = await Discord.ApiClient.GetCurrentUser().ConfigureAwait(false);
|
var model = await Discord.ApiClient.GetCurrentUser().ConfigureAwait(false);
|
||||||
Update(model, UpdateSource.Rest);
|
Update(model, UpdateSource.Rest);
|
||||||
}
|
}
|
||||||
public async Task Modify(Action<ModifyCurrentUserParams> func)
|
public async Task Modify(Action<ModifyCurrentUserParams> func)
|
||||||
{
|
{
|
||||||
if (func != null) throw new NullReferenceException(nameof(func));
|
if (func != null) throw new NullReferenceException(nameof(func));
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ namespace Discord
|
|||||||
public override DiscordClient Discord { get; }
|
public override DiscordClient Discord { get; }
|
||||||
|
|
||||||
public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, _avatarId);
|
public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, _avatarId);
|
||||||
public virtual Game? Game => null;
|
|
||||||
public string Mention => MentionUtils.Mention(this, false);
|
public string Mention => MentionUtils.Mention(this, false);
|
||||||
public string NicknameMention => MentionUtils.Mention(this, true);
|
public string NicknameMention => MentionUtils.Mention(this, true);
|
||||||
|
public virtual Game? Game => null;
|
||||||
public virtual UserStatus Status => UserStatus.Unknown;
|
public virtual UserStatus Status => UserStatus.Unknown;
|
||||||
|
|
||||||
public User(DiscordClient discord, Model model)
|
public User(DiscordClient discord, Model model)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Discord
|
|||||||
|
|
||||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||||
public new CachedPublicUser Recipient => base.Recipient as CachedPublicUser;
|
public new CachedPublicUser Recipient => base.Recipient as CachedPublicUser;
|
||||||
public IReadOnlyCollection<IUser> Members => ImmutableArray.Create<IUser>(Discord.CurrentUser, Recipient);
|
public IReadOnlyCollection<ICachedUser> Members => ImmutableArray.Create<ICachedUser>(Discord.CurrentUser, Recipient);
|
||||||
|
|
||||||
public CachedDMChannel(DiscordSocketClient discord, CachedPublicUser recipient, Model model)
|
public CachedDMChannel(DiscordSocketClient discord, CachedPublicUser recipient, Model model)
|
||||||
: base(discord, recipient, model)
|
: base(discord, recipient, model)
|
||||||
@@ -21,11 +21,11 @@ namespace Discord
|
|||||||
_messages = new MessageCache(Discord, this);
|
_messages = new MessageCache(Discord, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<IUser> GetUser(ulong id) => Task.FromResult(GetCachedUser(id));
|
public override Task<IUser> GetUser(ulong id) => Task.FromResult<IUser>(GetCachedUser(id));
|
||||||
public override Task<IReadOnlyCollection<IUser>> GetUsers() => Task.FromResult(Members);
|
public override Task<IReadOnlyCollection<IUser>> GetUsers() => Task.FromResult<IReadOnlyCollection<IUser>>(Members);
|
||||||
public override Task<IReadOnlyCollection<IUser>> GetUsers(int limit, int offset)
|
public override Task<IReadOnlyCollection<IUser>> GetUsers(int limit, int offset)
|
||||||
=> Task.FromResult<IReadOnlyCollection<IUser>>(Members.Skip(offset).Take(limit).ToImmutableArray());
|
=> Task.FromResult<IReadOnlyCollection<IUser>>(Members.Skip(offset).Take(limit).ToImmutableArray());
|
||||||
public IUser GetCachedUser(ulong id)
|
public ICachedUser GetCachedUser(ulong id)
|
||||||
{
|
{
|
||||||
var currentUser = Discord.CurrentUser;
|
var currentUser = Discord.CurrentUser;
|
||||||
if (id == Recipient.Id)
|
if (id == Recipient.Id)
|
||||||
@@ -48,7 +48,7 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
return await _messages.Download(fromMessageId, dir, limit).ConfigureAwait(false);
|
return await _messages.Download(fromMessageId, dir, limit).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
public CachedMessage AddCachedMessage(IUser author, MessageModel model)
|
public CachedMessage AddCachedMessage(ICachedUser author, MessageModel model)
|
||||||
{
|
{
|
||||||
var msg = new CachedMessage(this, author, model);
|
var msg = new CachedMessage(this, author, model);
|
||||||
_messages.Add(msg);
|
_messages.Add(msg);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ using ExtendedModel = Discord.API.Gateway.ExtendedGuild;
|
|||||||
using MemberModel = Discord.API.GuildMember;
|
using MemberModel = Discord.API.GuildMember;
|
||||||
using Model = Discord.API.Guild;
|
using Model = Discord.API.Guild;
|
||||||
using PresenceModel = Discord.API.Presence;
|
using PresenceModel = Discord.API.Presence;
|
||||||
|
using RoleModel = Discord.API.Role;
|
||||||
|
using VoiceStateModel = Discord.API.VoiceState;
|
||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
@@ -20,9 +22,11 @@ namespace Discord
|
|||||||
private ConcurrentHashSet<ulong> _channels;
|
private ConcurrentHashSet<ulong> _channels;
|
||||||
private ConcurrentDictionary<ulong, CachedGuildUser> _members;
|
private ConcurrentDictionary<ulong, CachedGuildUser> _members;
|
||||||
private ConcurrentDictionary<ulong, Presence> _presences;
|
private ConcurrentDictionary<ulong, Presence> _presences;
|
||||||
private int _userCount;
|
private ConcurrentDictionary<ulong, VoiceState> _voiceStates;
|
||||||
|
|
||||||
public bool Available { get; private set; } //TODO: Add to IGuild
|
public bool Available { get; private set; } //TODO: Add to IGuild
|
||||||
|
public int MemberCount { get; private set; }
|
||||||
|
public int DownloadedMemberCount { get; private set; }
|
||||||
|
|
||||||
public bool HasAllMembers => _downloaderPromise.Task.IsCompleted;
|
public bool HasAllMembers => _downloaderPromise.Task.IsCompleted;
|
||||||
public Task DownloaderPromise => _downloaderPromise.Task;
|
public Task DownloaderPromise => _downloaderPromise.Task;
|
||||||
@@ -32,9 +36,10 @@ namespace Discord
|
|||||||
public IReadOnlyCollection<ICachedGuildChannel> Channels => _channels.Select(x => GetCachedChannel(x)).ToReadOnlyCollection(_channels);
|
public IReadOnlyCollection<ICachedGuildChannel> Channels => _channels.Select(x => GetCachedChannel(x)).ToReadOnlyCollection(_channels);
|
||||||
public IReadOnlyCollection<CachedGuildUser> Members => _members.ToReadOnlyCollection();
|
public IReadOnlyCollection<CachedGuildUser> Members => _members.ToReadOnlyCollection();
|
||||||
|
|
||||||
public CachedGuild(DiscordSocketClient discord, Model model) : base(discord, model)
|
public CachedGuild(DiscordSocketClient discord, ExtendedModel model, DataStore dataStore) : base(discord, model)
|
||||||
{
|
{
|
||||||
_downloaderPromise = new TaskCompletionSource<bool>();
|
_downloaderPromise = new TaskCompletionSource<bool>();
|
||||||
|
Update(model, UpdateSource.Creation, dataStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(ExtendedModel model, UpdateSource source, DataStore dataStore)
|
public void Update(ExtendedModel model, UpdateSource source, DataStore dataStore)
|
||||||
@@ -52,6 +57,8 @@ namespace Discord
|
|||||||
_presences = new ConcurrentDictionary<ulong, Presence>();
|
_presences = new ConcurrentDictionary<ulong, Presence>();
|
||||||
if (_roles == null)
|
if (_roles == null)
|
||||||
_roles = new ConcurrentDictionary<ulong, Role>();
|
_roles = new ConcurrentDictionary<ulong, Role>();
|
||||||
|
if (_voiceStates == null)
|
||||||
|
_voiceStates = new ConcurrentDictionary<ulong, VoiceState>();
|
||||||
if (Emojis == null)
|
if (Emojis == null)
|
||||||
Emojis = ImmutableArray.Create<Emoji>();
|
Emojis = ImmutableArray.Create<Emoji>();
|
||||||
if (Features == null)
|
if (Features == null)
|
||||||
@@ -61,7 +68,7 @@ namespace Discord
|
|||||||
|
|
||||||
base.Update(model as Model, source);
|
base.Update(model as Model, source);
|
||||||
|
|
||||||
_userCount = model.MemberCount;
|
MemberCount = model.MemberCount;
|
||||||
|
|
||||||
var channels = new ConcurrentHashSet<ulong>();
|
var channels = new ConcurrentHashSet<ulong>();
|
||||||
if (model.Channels != null)
|
if (model.Channels != null)
|
||||||
@@ -75,7 +82,7 @@ namespace Discord
|
|||||||
if (model.Presences != null)
|
if (model.Presences != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < model.Presences.Length; i++)
|
for (int i = 0; i < model.Presences.Length; i++)
|
||||||
AddCachedPresence(model.Presences[i], presences);
|
AddOrUpdateCachedPresence(model.Presences[i], presences);
|
||||||
}
|
}
|
||||||
_presences = presences;
|
_presences = presences;
|
||||||
|
|
||||||
@@ -85,10 +92,19 @@ namespace Discord
|
|||||||
for (int i = 0; i < model.Members.Length; i++)
|
for (int i = 0; i < model.Members.Length; i++)
|
||||||
AddCachedUser(model.Members[i], members, dataStore);
|
AddCachedUser(model.Members[i], members, dataStore);
|
||||||
_downloaderPromise = new TaskCompletionSource<bool>();
|
_downloaderPromise = new TaskCompletionSource<bool>();
|
||||||
|
DownloadedMemberCount = model.Members.Length;
|
||||||
if (!model.Large)
|
if (!model.Large)
|
||||||
_downloaderPromise.SetResult(true);
|
_downloaderPromise.SetResult(true);
|
||||||
}
|
}
|
||||||
_members = members;
|
_members = members;
|
||||||
|
|
||||||
|
var voiceStates = new ConcurrentDictionary<ulong, VoiceState>();
|
||||||
|
if (model.VoiceStates != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < model.VoiceStates.Length; i++)
|
||||||
|
AddOrUpdateCachedVoiceState(model.VoiceStates[i], _voiceStates);
|
||||||
|
}
|
||||||
|
_voiceStates = voiceStates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<IGuildChannel> GetChannel(ulong id) => Task.FromResult<IGuildChannel>(GetCachedChannel(id));
|
public override Task<IGuildChannel> GetChannel(ulong id) => Task.FromResult<IGuildChannel>(GetCachedChannel(id));
|
||||||
@@ -108,7 +124,7 @@ namespace Discord
|
|||||||
(channels ?? _channels).TryRemove(id);
|
(channels ?? _channels).TryRemove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Presence AddCachedPresence(PresenceModel model, ConcurrentDictionary<ulong, Presence> presences = null)
|
public Presence AddOrUpdateCachedPresence(PresenceModel model, ConcurrentDictionary<ulong, Presence> presences = null)
|
||||||
{
|
{
|
||||||
var game = model.Game != null ? new Game(model.Game) : (Game?)null;
|
var game = model.Game != null ? new Game(model.Game) : (Game?)null;
|
||||||
var presence = new Presence(model.Status, game);
|
var presence = new Presence(model.Status, game);
|
||||||
@@ -130,6 +146,42 @@ namespace Discord
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Role AddCachedRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null)
|
||||||
|
{
|
||||||
|
var role = new Role(this, model);
|
||||||
|
(roles ?? _roles)[model.Id] = role;
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
public Role RemoveCachedRole(ulong id)
|
||||||
|
{
|
||||||
|
Role role;
|
||||||
|
if (_roles.TryRemove(id, out role))
|
||||||
|
return role;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoiceState AddOrUpdateCachedVoiceState(VoiceStateModel model, ConcurrentDictionary<ulong, VoiceState> voiceStates = null)
|
||||||
|
{
|
||||||
|
var voiceChannel = GetCachedChannel(model.ChannelId.Value) as CachedVoiceChannel;
|
||||||
|
var voiceState = new VoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress);
|
||||||
|
(voiceStates ?? _voiceStates)[model.UserId] = voiceState;
|
||||||
|
return voiceState;
|
||||||
|
}
|
||||||
|
public VoiceState? GetCachedVoiceState(ulong id)
|
||||||
|
{
|
||||||
|
VoiceState voiceState;
|
||||||
|
if (_voiceStates.TryGetValue(id, out voiceState))
|
||||||
|
return voiceState;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public VoiceState? RemoveCachedVoiceState(ulong id)
|
||||||
|
{
|
||||||
|
VoiceState voiceState;
|
||||||
|
if (_voiceStates.TryRemove(id, out voiceState))
|
||||||
|
return voiceState;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult<IGuildUser>(GetCachedUser(id));
|
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult<IGuildUser>(GetCachedUser(id));
|
||||||
public override Task<IGuildUser> GetCurrentUser()
|
public override Task<IGuildUser> GetCurrentUser()
|
||||||
=> Task.FromResult<IGuildUser>(CurrentUser);
|
=> Task.FromResult<IGuildUser>(CurrentUser);
|
||||||
@@ -140,10 +192,11 @@ namespace Discord
|
|||||||
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.OrderBy(x => x.Id).Skip(offset).Take(limit).ToImmutableArray());
|
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.OrderBy(x => x.Id).Skip(offset).Take(limit).ToImmutableArray());
|
||||||
public CachedGuildUser AddCachedUser(MemberModel model, ConcurrentDictionary<ulong, CachedGuildUser> members = null, DataStore dataStore = null)
|
public CachedGuildUser AddCachedUser(MemberModel model, ConcurrentDictionary<ulong, CachedGuildUser> members = null, DataStore dataStore = null)
|
||||||
{
|
{
|
||||||
var user = Discord.AddCachedUser(model.User);
|
var user = Discord.GetOrAddCachedUser(model.User);
|
||||||
var member = new CachedGuildUser(this, user, model);
|
var member = new CachedGuildUser(this, user, model);
|
||||||
(members ?? _members)[user.Id] = member;
|
(members ?? _members)[user.Id] = member;
|
||||||
user.AddRef();
|
user.AddRef();
|
||||||
|
DownloadedMemberCount++;
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
public CachedGuildUser GetCachedUser(ulong id)
|
public CachedGuildUser GetCachedUser(ulong id)
|
||||||
@@ -160,7 +213,6 @@ namespace Discord
|
|||||||
return member;
|
return member;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadMembers()
|
public async Task DownloadMembers()
|
||||||
{
|
{
|
||||||
if (!HasAllMembers)
|
if (!HasAllMembers)
|
||||||
@@ -169,7 +221,7 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
public void CompleteDownloadMembers()
|
public void CompleteDownloadMembers()
|
||||||
{
|
{
|
||||||
_downloaderPromise.SetResult(true);
|
_downloaderPromise.TrySetResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedGuild Clone() => MemberwiseClone() as CachedGuild;
|
public CachedGuild Clone() => MemberwiseClone() as CachedGuild;
|
||||||
|
|||||||
@@ -2,11 +2,21 @@
|
|||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
internal class CachedGuildUser : GuildUser, ICachedEntity<ulong>
|
internal class CachedGuildUser : GuildUser, ICachedUser
|
||||||
{
|
{
|
||||||
public VoiceChannel VoiceChannel { get; private set; }
|
|
||||||
|
|
||||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||||
|
public new CachedGuild Guild => base.Guild as CachedGuild;
|
||||||
|
public new CachedPublicUser User => base.User as CachedPublicUser;
|
||||||
|
|
||||||
|
public Presence? Presence => Guild.GetCachedPresence(Id);
|
||||||
|
public override Game? Game => Presence?.Game;
|
||||||
|
public override UserStatus Status => Presence?.Status ?? UserStatus.Offline;
|
||||||
|
|
||||||
|
public VoiceState? VoiceState => Guild.GetCachedVoiceState(Id);
|
||||||
|
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false;
|
||||||
|
public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false;
|
||||||
|
public bool IsSuppressed => VoiceState?.IsSuppressed ?? false;
|
||||||
|
public CachedVoiceChannel VoiceChannel => VoiceState?.VoiceChannel;
|
||||||
|
|
||||||
public CachedGuildUser(CachedGuild guild, CachedPublicUser user, Model model)
|
public CachedGuildUser(CachedGuild guild, CachedPublicUser user, Model model)
|
||||||
: base(guild, user, model)
|
: base(guild, user, model)
|
||||||
@@ -14,5 +24,6 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser;
|
public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser;
|
||||||
|
ICachedUser ICachedUser.Clone() => Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
using ChannelModel = Discord.API.Channel;
|
using ChannelModel = Discord.API.Channel;
|
||||||
using Model = Discord.API.User;
|
using Model = Discord.API.User;
|
||||||
|
using PresenceModel = Discord.API.Presence;
|
||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
internal class CachedPublicUser : User, ICachedEntity<ulong>
|
internal class CachedPublicUser : User, ICachedUser
|
||||||
{
|
{
|
||||||
private int _references;
|
private int _references;
|
||||||
|
private Game? _game;
|
||||||
|
private UserStatus _status;
|
||||||
|
|
||||||
public CachedDMChannel DMChannel { get; private set; }
|
public CachedDMChannel DMChannel { get; private set; }
|
||||||
|
|
||||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||||
|
public override UserStatus Status => _status;
|
||||||
|
public override Game? Game => _game;
|
||||||
|
|
||||||
public CachedPublicUser(DiscordSocketClient discord, Model model)
|
public CachedPublicUser(DiscordSocketClient discord, Model model)
|
||||||
: base(discord, model)
|
: base(discord, model)
|
||||||
@@ -39,6 +44,16 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Update(PresenceModel model, UpdateSource source)
|
||||||
|
{
|
||||||
|
if (source == UpdateSource.Rest) return;
|
||||||
|
|
||||||
|
var game = model.Game != null ? new Game(model.Game) : (Game?)null;
|
||||||
|
|
||||||
|
_status = model.Status;
|
||||||
|
_game = game;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddRef()
|
public void AddRef()
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
@@ -54,5 +69,6 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CachedPublicUser Clone() => MemberwiseClone() as CachedPublicUser;
|
public CachedPublicUser Clone() => MemberwiseClone() as CachedPublicUser;
|
||||||
|
ICachedUser ICachedUser.Clone() => Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
internal class CachedSelfUser : SelfUser, ICachedEntity<ulong>
|
internal class CachedSelfUser : SelfUser, ICachedUser
|
||||||
{
|
{
|
||||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||||
|
|
||||||
@@ -12,5 +12,6 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CachedSelfUser Clone() => MemberwiseClone() as CachedSelfUser;
|
public CachedSelfUser Clone() => MemberwiseClone() as CachedSelfUser;
|
||||||
|
ICachedUser ICachedUser.Clone() => Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Discord
|
|||||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||||
public new CachedGuild Guild => base.Guild as CachedGuild;
|
public new CachedGuild Guild => base.Guild as CachedGuild;
|
||||||
|
|
||||||
public IReadOnlyCollection<IGuildUser> Members
|
public IReadOnlyCollection<CachedGuildUser> Members
|
||||||
=> Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray();
|
=> Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray();
|
||||||
|
|
||||||
public CachedTextChannel(CachedGuild guild, Model model)
|
public CachedTextChannel(CachedGuild guild, Model model)
|
||||||
@@ -23,11 +23,11 @@ namespace Discord
|
|||||||
_messages = new MessageCache(Discord, this);
|
_messages = new MessageCache(Discord, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult(GetCachedUser(id));
|
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult<IGuildUser>(GetCachedUser(id));
|
||||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers() => Task.FromResult(Members);
|
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members);
|
||||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers(int limit, int offset)
|
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers(int limit, int offset)
|
||||||
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.Skip(offset).Take(limit).ToImmutableArray());
|
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.Skip(offset).Take(limit).ToImmutableArray());
|
||||||
public IGuildUser GetCachedUser(ulong id)
|
public CachedGuildUser GetCachedUser(ulong id)
|
||||||
{
|
{
|
||||||
var user = Guild.GetCachedUser(id);
|
var user = Guild.GetCachedUser(id);
|
||||||
if (user != null && Permissions.GetValue(Permissions.ResolveChannel(user, this, user.GuildPermissions.RawValue), ChannelPermission.ReadMessages))
|
if (user != null && Permissions.GetValue(Permissions.ResolveChannel(user, this, user.GuildPermissions.RawValue), ChannelPermission.ReadMessages))
|
||||||
@@ -48,7 +48,7 @@ namespace Discord
|
|||||||
return await _messages.Download(fromMessageId, dir, limit).ConfigureAwait(false);
|
return await _messages.Download(fromMessageId, dir, limit).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedMessage AddCachedMessage(IUser author, MessageModel model)
|
public CachedMessage AddCachedMessage(ICachedUser author, MessageModel model)
|
||||||
{
|
{
|
||||||
var msg = new CachedMessage(this, author, model);
|
var msg = new CachedMessage(this, author, model);
|
||||||
_messages.Add(msg);
|
_messages.Add(msg);
|
||||||
@@ -65,10 +65,10 @@ namespace Discord
|
|||||||
|
|
||||||
public CachedTextChannel Clone() => MemberwiseClone() as CachedTextChannel;
|
public CachedTextChannel Clone() => MemberwiseClone() as CachedTextChannel;
|
||||||
|
|
||||||
IReadOnlyCollection<IUser> ICachedMessageChannel.Members => Members;
|
IReadOnlyCollection<ICachedUser> ICachedMessageChannel.Members => Members;
|
||||||
|
|
||||||
IMessage IMessageChannel.GetCachedMessage(ulong id) => GetCachedMessage(id);
|
IMessage IMessageChannel.GetCachedMessage(ulong id) => GetCachedMessage(id);
|
||||||
IUser ICachedMessageChannel.GetCachedUser(ulong id) => GetCachedUser(id);
|
ICachedUser ICachedMessageChannel.GetCachedUser(ulong id) => GetCachedUser(id);
|
||||||
ICachedChannel ICachedChannel.Clone() => Clone();
|
ICachedChannel ICachedChannel.Clone() => Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
internal interface ICachedMessageChannel : ICachedChannel, IMessageChannel
|
internal interface ICachedMessageChannel : ICachedChannel, IMessageChannel
|
||||||
{
|
{
|
||||||
IReadOnlyCollection<IUser> Members { get; }
|
IReadOnlyCollection<ICachedUser> Members { get; }
|
||||||
|
|
||||||
CachedMessage AddCachedMessage(IUser author, MessageModel model);
|
CachedMessage AddCachedMessage(ICachedUser author, MessageModel model);
|
||||||
new CachedMessage GetCachedMessage(ulong id);
|
new CachedMessage GetCachedMessage(ulong id);
|
||||||
CachedMessage RemoveCachedMessage(ulong id);
|
CachedMessage RemoveCachedMessage(ulong id);
|
||||||
|
|
||||||
IUser GetCachedUser(ulong id);
|
ICachedUser GetCachedUser(ulong id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/Discord.Net/Entities/WebSocket/ICachedUser.cs
Normal file
7
src/Discord.Net/Entities/WebSocket/ICachedUser.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Discord
|
||||||
|
{
|
||||||
|
internal interface ICachedUser : IUser, ICachedEntity<ulong>
|
||||||
|
{
|
||||||
|
ICachedUser Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*using System;
|
|
||||||
using Model = Discord.API.MemberVoiceState;
|
|
||||||
|
|
||||||
namespace Discord.WebSocket
|
|
||||||
{
|
|
||||||
internal class VoiceState : IVoiceState
|
|
||||||
{
|
|
||||||
[Flags]
|
|
||||||
private enum VoiceStates : byte
|
|
||||||
{
|
|
||||||
None = 0x0,
|
|
||||||
Muted = 0x01,
|
|
||||||
Deafened = 0x02,
|
|
||||||
Suppressed = 0x4,
|
|
||||||
SelfMuted = 0x10,
|
|
||||||
SelfDeafened = 0x20,
|
|
||||||
}
|
|
||||||
|
|
||||||
private VoiceStates _voiceStates;
|
|
||||||
|
|
||||||
public Guild Guild { get; }
|
|
||||||
public ulong UserId { get; }
|
|
||||||
|
|
||||||
/// <summary> Gets this user's current voice channel. </summary>
|
|
||||||
public VoiceChannel VoiceChannel { get; set; }
|
|
||||||
|
|
||||||
/// <summary> Returns true if this user has marked themselves as muted. </summary>
|
|
||||||
public bool IsSelfMuted => (_voiceStates & VoiceStates.SelfMuted) != 0;
|
|
||||||
/// <summary> Returns true if this user has marked themselves as deafened. </summary>
|
|
||||||
public bool IsSelfDeafened => (_voiceStates & VoiceStates.SelfDeafened) != 0;
|
|
||||||
/// <summary> Returns true if the guild is blocking audio from this user. </summary>
|
|
||||||
public bool IsMuted => (_voiceStates & VoiceStates.Muted) != 0;
|
|
||||||
/// <summary> Returns true if the guild is blocking audio to this user. </summary>
|
|
||||||
public bool IsDeafened => (_voiceStates & VoiceStates.Deafened) != 0;
|
|
||||||
/// <summary> Returns true if the guild is temporarily blocking audio to/from this user. </summary>
|
|
||||||
public bool IsSuppressed => (_voiceStates & VoiceStates.Suppressed) != 0;
|
|
||||||
|
|
||||||
public VoiceState(ulong userId, Guild guild)
|
|
||||||
{
|
|
||||||
UserId = userId;
|
|
||||||
Guild = guild;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update(Model model, UpdateSource source)
|
|
||||||
{
|
|
||||||
if (model.IsMuted == true)
|
|
||||||
_voiceStates |= VoiceStates.Muted;
|
|
||||||
else if (model.IsMuted == false)
|
|
||||||
_voiceStates &= ~VoiceStates.Muted;
|
|
||||||
|
|
||||||
if (model.IsDeafened == true)
|
|
||||||
_voiceStates |= VoiceStates.Deafened;
|
|
||||||
else if (model.IsDeafened == false)
|
|
||||||
_voiceStates &= ~VoiceStates.Deafened;
|
|
||||||
|
|
||||||
if (model.IsSuppressed == true)
|
|
||||||
_voiceStates |= VoiceStates.Suppressed;
|
|
||||||
else if (model.IsSuppressed == false)
|
|
||||||
_voiceStates &= ~VoiceStates.Suppressed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
42
src/Discord.Net/Entities/WebSocket/VoiceState.cs
Normal file
42
src/Discord.Net/Entities/WebSocket/VoiceState.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Discord
|
||||||
|
{
|
||||||
|
internal struct VoiceState : IVoiceState
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
private enum Flags : byte
|
||||||
|
{
|
||||||
|
None = 0x0,
|
||||||
|
Suppressed = 0x1,
|
||||||
|
SelfMuted = 0x2,
|
||||||
|
SelfDeafened = 0x4,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Flags _voiceStates;
|
||||||
|
|
||||||
|
public CachedVoiceChannel VoiceChannel { get; }
|
||||||
|
public string VoiceSessionId { get; }
|
||||||
|
|
||||||
|
public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 0;
|
||||||
|
public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0;
|
||||||
|
public bool IsSuppressed => (_voiceStates & Flags.Suppressed) != 0;
|
||||||
|
|
||||||
|
public VoiceState(CachedVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed)
|
||||||
|
{
|
||||||
|
VoiceChannel = voiceChannel;
|
||||||
|
VoiceSessionId = sessionId;
|
||||||
|
|
||||||
|
Flags voiceStates = Flags.None;
|
||||||
|
if (isSelfMuted)
|
||||||
|
voiceStates |= Flags.SelfMuted;
|
||||||
|
if (isSelfDeafened)
|
||||||
|
voiceStates |= Flags.SelfDeafened;
|
||||||
|
if (isSuppressed)
|
||||||
|
voiceStates |= Flags.Suppressed;
|
||||||
|
_voiceStates = voiceStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
IVoiceChannel IVoiceState.VoiceChannel => VoiceChannel;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
"buildOptions": {
|
"buildOptions": {
|
||||||
"allowUnsafe": true,
|
"allowUnsafe": true,
|
||||||
|
"define": [ "BENCHMARK" ],
|
||||||
"warningsAsErrors": false
|
"warningsAsErrors": false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user