From 31b0085ae34c06ca2734a58a45f9b83b6f32e99c Mon Sep 17 00:00:00 2001 From: RogueException Date: Fri, 24 Jun 2016 17:45:08 -0300 Subject: [PATCH] Reworked Presence and VoiceState, added updated events --- src/Discord.Net/DiscordSocketClient.Events.cs | 190 ++++++++++++++++++ src/Discord.Net/DiscordSocketClient.cs | 142 ++++--------- src/Discord.Net/Entities/Users/GuildUser.cs | 23 +-- src/Discord.Net/Entities/Users/IGuildUser.cs | 4 - src/Discord.Net/Entities/Users/IVoiceState.cs | 4 + .../Entities/WebSocket/CachedGuild.cs | 2 +- .../Entities/WebSocket/CachedGuildUser.cs | 26 ++- .../Entities/WebSocket/VoiceState.cs | 22 +- 8 files changed, 277 insertions(+), 136 deletions(-) create mode 100644 src/Discord.Net/DiscordSocketClient.Events.cs diff --git a/src/Discord.Net/DiscordSocketClient.Events.cs b/src/Discord.Net/DiscordSocketClient.Events.cs new file mode 100644 index 000000000..2a16f7b65 --- /dev/null +++ b/src/Discord.Net/DiscordSocketClient.Events.cs @@ -0,0 +1,190 @@ +using System; +using System.Threading.Tasks; + +namespace Discord +{ + public partial class DiscordSocketClient + { + //General + public event Func Connected + { + add { _connectedEvent.Add(value); } + remove { _connectedEvent.Remove(value); } + } + private readonly AsyncEvent> _connectedEvent = new AsyncEvent>(); + public event Func Disconnected + { + add { _disconnectedEvent.Add(value); } + remove { _disconnectedEvent.Remove(value); } + } + private readonly AsyncEvent> _disconnectedEvent = new AsyncEvent>(); + public event Func Ready + { + add { _readyEvent.Add(value); } + remove { _readyEvent.Remove(value); } + } + private readonly AsyncEvent> _readyEvent = new AsyncEvent>(); + public event Func LatencyUpdated + { + add { _latencyUpdatedEvent.Add(value); } + remove { _latencyUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _latencyUpdatedEvent = new AsyncEvent>(); + + //Channels + public event Func ChannelCreated + { + add { _channelCreatedEvent.Add(value); } + remove { _channelCreatedEvent.Remove(value); } + } + private readonly AsyncEvent> _channelCreatedEvent = new AsyncEvent>(); + public event Func ChannelDestroyed + { + add { _channelDestroyedEvent.Add(value); } + remove { _channelDestroyedEvent.Remove(value); } + } + private readonly AsyncEvent> _channelDestroyedEvent = new AsyncEvent>(); + public event Func ChannelUpdated + { + add { _channelUpdatedEvent.Add(value); } + remove { _channelUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _channelUpdatedEvent = new AsyncEvent>(); + + //Messages + public event Func MessageReceived + { + add { _messageReceivedEvent.Add(value); } + remove { _messageReceivedEvent.Remove(value); } + } + private readonly AsyncEvent> _messageReceivedEvent = new AsyncEvent>(); + public event Func, Task> MessageDeleted + { + add { _messageDeletedEvent.Add(value); } + remove { _messageDeletedEvent.Remove(value); } + } + private readonly AsyncEvent, Task>> _messageDeletedEvent = new AsyncEvent, Task>>(); + public event Func, IMessage, Task> MessageUpdated + { + add { _messageUpdatedEvent.Add(value); } + remove { _messageUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent, IMessage, Task>> _messageUpdatedEvent = new AsyncEvent, IMessage, Task>>(); + + //Roles + public event Func RoleCreated + { + add { _roleCreatedEvent.Add(value); } + remove { _roleCreatedEvent.Remove(value); } + } + private readonly AsyncEvent> _roleCreatedEvent = new AsyncEvent>(); + public event Func RoleDeleted + { + add { _roleDeletedEvent.Add(value); } + remove { _roleDeletedEvent.Remove(value); } + } + private readonly AsyncEvent> _roleDeletedEvent = new AsyncEvent>(); + public event Func RoleUpdated + { + add { _roleUpdatedEvent.Add(value); } + remove { _roleUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _roleUpdatedEvent = new AsyncEvent>(); + + //Guilds + public event Func JoinedGuild + { + add { _joinedGuildEvent.Add(value); } + remove { _joinedGuildEvent.Remove(value); } + } + private AsyncEvent> _joinedGuildEvent = new AsyncEvent>(); + public event Func LeftGuild + { + add { _leftGuildEvent.Add(value); } + remove { _leftGuildEvent.Remove(value); } + } + private AsyncEvent> _leftGuildEvent = new AsyncEvent>(); + public event Func GuildAvailable + { + add { _guildAvailableEvent.Add(value); } + remove { _guildAvailableEvent.Remove(value); } + } + private AsyncEvent> _guildAvailableEvent = new AsyncEvent>(); + public event Func GuildUnavailable + { + add { _guildUnavailableEvent.Add(value); } + remove { _guildUnavailableEvent.Remove(value); } + } + private AsyncEvent> _guildUnavailableEvent = new AsyncEvent>(); + public event Func GuildDownloadedMembers + { + add { _guildDownloadedMembersEvent.Add(value); } + remove { _guildDownloadedMembersEvent.Remove(value); } + } + private AsyncEvent> _guildDownloadedMembersEvent = new AsyncEvent>(); + public event Func GuildUpdated + { + add { _guildUpdatedEvent.Add(value); } + remove { _guildUpdatedEvent.Remove(value); } + } + private AsyncEvent> _guildUpdatedEvent = new AsyncEvent>(); + + //Users + public event Func UserJoined + { + add { _userJoinedEvent.Add(value); } + remove { _userJoinedEvent.Remove(value); } + } + private readonly AsyncEvent> _userJoinedEvent = new AsyncEvent>(); + public event Func UserLeft + { + add { _userLeftEvent.Add(value); } + remove { _userLeftEvent.Remove(value); } + } + private readonly AsyncEvent> _userLeftEvent = new AsyncEvent>(); + public event Func UserBanned + { + add { _userBannedEvent.Add(value); } + remove { _userBannedEvent.Remove(value); } + } + private readonly AsyncEvent> _userBannedEvent = new AsyncEvent>(); + public event Func UserUnbanned + { + add { _userUnbannedEvent.Add(value); } + remove { _userUnbannedEvent.Remove(value); } + } + private readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); + public event Func UserUpdated + { + add { _userUpdatedEvent.Add(value); } + remove { _userUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _userUpdatedEvent = new AsyncEvent>(); + public event Func UserPresenceUpdated + { + add { _userPresenceUpdatedEvent.Add(value); } + remove { _userPresenceUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _userPresenceUpdatedEvent = new AsyncEvent>(); + public event Func UserVoiceStateUpdated + { + add { _userVoiceStateUpdatedEvent.Add(value); } + remove { _userVoiceStateUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _userVoiceStateUpdatedEvent = new AsyncEvent>(); + public event Func CurrentUserUpdated + { + add { _selfUpdatedEvent.Add(value); } + remove { _selfUpdatedEvent.Remove(value); } + } + private readonly AsyncEvent> _selfUpdatedEvent = new AsyncEvent>(); + public event Func UserIsTyping + { + add { _userIsTypingEvent.Add(value); } + remove { _userIsTypingEvent.Remove(value); } + } + private readonly AsyncEvent> _userIsTypingEvent = new AsyncEvent>(); + + //TODO: Add PresenceUpdated? VoiceStateUpdated?, VoiceConnected, VoiceDisconnected; + } +} diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs index 725927b1b..272ea5444 100644 --- a/src/Discord.Net/DiscordSocketClient.cs +++ b/src/Discord.Net/DiscordSocketClient.cs @@ -19,77 +19,8 @@ namespace Discord //TODO: Add event docstrings //TODO: Add reconnect logic (+ensure the heartbeat task to shut down) //TODO: Add resume logic - public class DiscordSocketClient : DiscordClient, IDiscordClient + public partial class DiscordSocketClient : DiscordClient, IDiscordClient { - private object _eventLock = new object(); - - //General - public event Func Connected { add { _connectedEvent.Add(value); } remove { _connectedEvent.Remove(value); } } - private readonly AsyncEvent> _connectedEvent = new AsyncEvent>(); - public event Func Disconnected { add { _disconnectedEvent.Add(value); } remove { _disconnectedEvent.Remove(value); } } - private readonly AsyncEvent> _disconnectedEvent = new AsyncEvent>(); - public event Func Ready { add { _readyEvent.Add(value); } remove { _readyEvent.Remove(value); } } - private readonly AsyncEvent> _readyEvent = new AsyncEvent>(); - - public event Func LatencyUpdated { add { _latencyUpdatedEvent.Add(value); } remove { _latencyUpdatedEvent.Remove(value); } } - private readonly AsyncEvent> _latencyUpdatedEvent = new AsyncEvent>(); - - //Channels - public event Func ChannelCreated { add { _channelCreatedEvent.Add(value); } remove { _channelCreatedEvent.Remove(value); } } - private readonly AsyncEvent> _channelCreatedEvent = new AsyncEvent>(); - public event Func ChannelDestroyed { add { _channelDestroyedEvent.Add(value); } remove { _channelDestroyedEvent.Remove(value); } } - private readonly AsyncEvent> _channelDestroyedEvent = new AsyncEvent>(); - public event Func ChannelUpdated { add { _channelUpdatedEvent.Add(value); } remove { _channelUpdatedEvent.Remove(value); } } - private readonly AsyncEvent> _channelUpdatedEvent = new AsyncEvent>(); - - //Messages - public event Func MessageReceived { add { _messageReceivedEvent.Add(value); } remove { _messageReceivedEvent.Remove(value); } } - private readonly AsyncEvent> _messageReceivedEvent = new AsyncEvent>(); - public event Func, Task> MessageDeleted { add { _messageDeletedEvent.Add(value); } remove { _messageDeletedEvent.Remove(value); } } - private readonly AsyncEvent, Task>> _messageDeletedEvent = new AsyncEvent, Task>>(); - public event Func, IMessage, Task> MessageUpdated { add { _messageUpdatedEvent.Add(value); } remove { _messageUpdatedEvent.Remove(value); } } - private readonly AsyncEvent, IMessage, Task>> _messageUpdatedEvent = new AsyncEvent, IMessage, Task>>(); - - //Roles - public event Func RoleCreated { add { _roleCreatedEvent.Add(value); } remove { _roleCreatedEvent.Remove(value); } } - private readonly AsyncEvent> _roleCreatedEvent = new AsyncEvent>(); - public event Func RoleDeleted { add { _roleDeletedEvent.Add(value); } remove { _roleDeletedEvent.Remove(value); } } - private readonly AsyncEvent> _roleDeletedEvent = new AsyncEvent>(); - public event Func RoleUpdated { add { _roleUpdatedEvent.Add(value); } remove { _roleUpdatedEvent.Remove(value); } } - private readonly AsyncEvent> _roleUpdatedEvent = new AsyncEvent>(); - - //Guilds - public event Func JoinedGuild { add { _joinedGuildEvent.Add(value); } remove { _joinedGuildEvent.Remove(value); } } - private AsyncEvent> _joinedGuildEvent = new AsyncEvent>(); - public event Func LeftGuild { add { _leftGuildEvent.Add(value); } remove { _leftGuildEvent.Remove(value); } } - private AsyncEvent> _leftGuildEvent = new AsyncEvent>(); - public event Func GuildAvailable { add { _guildAvailableEvent.Add(value); } remove { _guildAvailableEvent.Remove(value); } } - private AsyncEvent> _guildAvailableEvent = new AsyncEvent>(); - public event Func GuildUnavailable { add { _guildUnavailableEvent.Add(value); } remove { _guildUnavailableEvent.Remove(value); } } - private AsyncEvent> _guildUnavailableEvent = new AsyncEvent>(); - public event Func GuildDownloadedMembers { add { _guildDownloadedMembersEvent.Add(value); } remove { _guildDownloadedMembersEvent.Remove(value); } } - private AsyncEvent> _guildDownloadedMembersEvent = new AsyncEvent>(); - public event Func GuildUpdated { add { _guildUpdatedEvent.Add(value); } remove { _guildUpdatedEvent.Remove(value); } } - private AsyncEvent> _guildUpdatedEvent = new AsyncEvent>(); - - //Users - public event Func UserJoined { add { _userJoinedEvent.Add(value); } remove { _userJoinedEvent.Remove(value); } } - private readonly AsyncEvent> _userJoinedEvent = new AsyncEvent>(); - public event Func UserLeft { add { _userLeftEvent.Add(value); } remove { _userLeftEvent.Remove(value); } } - private readonly AsyncEvent> _userLeftEvent = new AsyncEvent>(); - public event Func UserBanned { add { _userBannedEvent.Add(value); } remove { _userBannedEvent.Remove(value); } } - private readonly AsyncEvent> _userBannedEvent = new AsyncEvent>(); - public event Func UserUnbanned { add { _userUnbannedEvent.Add(value); } remove { _userUnbannedEvent.Remove(value); } } - private readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); - public event Func, IGuildUser, Task> UserUpdated { add { _userUpdatedEvent.Add(value); } remove { _userUpdatedEvent.Remove(value); } } - private readonly AsyncEvent, IGuildUser, Task>> _userUpdatedEvent = new AsyncEvent, IGuildUser, Task>>(); - public event Func CurrentUserUpdated { add { _selfUpdatedEvent.Add(value); } remove { _selfUpdatedEvent.Remove(value); } } - private readonly AsyncEvent> _selfUpdatedEvent = new AsyncEvent>(); - public event Func UserIsTyping { add { _userIsTypingEvent.Add(value); } remove { _userIsTypingEvent.Remove(value); } } - private readonly AsyncEvent> _userIsTypingEvent = new AsyncEvent>(); - - //TODO: Add PresenceUpdated? VoiceStateUpdated?, VoiceConnected, VoiceDisconnected; - private readonly ConcurrentQueue _largeGuilds; private readonly Logger _gatewayLogger; #if BENCHMARK @@ -1066,19 +997,20 @@ namespace Discord break; } + IPresence before; var user = guild.GetUser(data.User.Id); if (user != null) { - var before = user.Clone(); + before = user.Presence.Clone(); user.Update(data, UpdateSource.WebSocket); - await _userUpdatedEvent.InvokeAsync(before, user).ConfigureAwait(false); } else { + before = new Presence(null, UserStatus.Offline); user = guild.AddOrUpdateUser(data, DataStore); - user.Update(data, UpdateSource.WebSocket); - await _userUpdatedEvent.InvokeAsync(Optional.Create(), user).ConfigureAwait(false); } + + await _userPresenceUpdatedEvent.InvokeAsync(user, before, user).ConfigureAwait(false); } else { @@ -1103,6 +1035,26 @@ namespace Discord } break; + //Users + case "USER_UPDATE": + { + await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); + + var data = (payload as JToken).ToObject(_serializer); + if (data.Id == CurrentUser.Id) + { + var before = CurrentUser.Clone(); + CurrentUser.Update(data, UpdateSource.WebSocket); + await _selfUpdatedEvent.InvokeAsync(before, CurrentUser).ConfigureAwait(false); + } + else + { + await _gatewayLogger.WarningAsync("Received USER_UPDATE for wrong user.").ConfigureAwait(false); + return; + } + } + break; + //Voice case "VOICE_STATE_UPDATE": { @@ -1114,17 +1066,27 @@ namespace Discord var guild = DataStore.GetGuild(data.GuildId.Value); if (guild != null) { - if (data.ChannelId == null) - guild.RemoveVoiceState(data.UserId); + VoiceState before, after; + if (data.ChannelId != null) + { + before = guild.GetVoiceState(data.UserId)?.Clone() ?? new VoiceState(null, null, false, false, false); + after = guild.AddOrUpdateVoiceState(data, DataStore); + } else - guild.AddOrUpdateVoiceState(data, DataStore); + { + before = guild.RemoveVoiceState(data.UserId) ?? new VoiceState(null, null, false, false, false); + after = new VoiceState(null, data); + } var user = guild.GetUser(data.UserId); if (user != null) { - var before = user.Clone(); - user.Update(data, UpdateSource.WebSocket); - await _userUpdatedEvent.InvokeAsync(before, user).ConfigureAwait(false); + await _userVoiceStateUpdatedEvent.InvokeAsync(user, before, after).ConfigureAwait(false); + } + else + { + await _gatewayLogger.WarningAsync("VOICE_STATE_UPDATE referenced an unknown user.").ConfigureAwait(false); + return; } } else @@ -1136,26 +1098,6 @@ namespace Discord } break; - //Settings - case "USER_UPDATE": - { - await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false); - - var data = (payload as JToken).ToObject(_serializer); - if (data.Id == CurrentUser.Id) - { - var before = CurrentUser.Clone(); - CurrentUser.Update(data, UpdateSource.WebSocket); - await _selfUpdatedEvent.InvokeAsync(before, CurrentUser).ConfigureAwait(false); - } - else - { - await _gatewayLogger.WarningAsync("Received USER_UPDATE for wrong user.").ConfigureAwait(false); - return; - } - } - break; - //Ignored case "USER_SETTINGS_UPDATE": await _gatewayLogger.DebugAsync("Ignored Dispatch (USER_SETTINGS_UPDATE)").ConfigureAwait(false); diff --git a/src/Discord.Net/Entities/Users/GuildUser.cs b/src/Discord.Net/Entities/Users/GuildUser.cs index 0d4784417..7f21ee279 100644 --- a/src/Discord.Net/Entities/Users/GuildUser.cs +++ b/src/Discord.Net/Entities/Users/GuildUser.cs @@ -15,9 +15,7 @@ namespace Discord internal class GuildUser : IGuildUser, ISnowflakeEntity { private long? _joinedAtTicks; - - public bool IsDeaf { get; private set; } - public bool IsMute { get; private set; } + public string Nickname { get; private set; } public GuildPermissions GuildPermissions { get; private set; } @@ -59,11 +57,7 @@ namespace Discord public void Update(Model model, UpdateSource source) { if (source == UpdateSource.Rest && IsAttached) return; - - //if (model.Deaf.IsSpecified) - IsDeaf = model.Deaf; - //if (model.Mute.IsSpecified) - IsMute = model.Mute; + //if (model.JoinedAt.IsSpecified) _joinedAtTicks = model.JoinedAt.UtcTicks; if (model.Nick.IsSpecified) @@ -81,13 +75,6 @@ namespace Discord if (model.Nick.IsSpecified) Nickname = model.Nick.Value; } - public void Update(VoiceStateModel model, UpdateSource source) - { - if (source == UpdateSource.Rest && IsAttached) return; - - IsDeaf = model.Deaf; - IsMute = model.Mute; - } private void UpdateRoles(ulong[] roleIds) { var roles = ImmutableArray.CreateBuilder(roleIds.Length + 1); @@ -127,10 +114,6 @@ namespace Discord if (!isCurrentUser || args.Deaf.IsSpecified || args.Mute.IsSpecified || args.RoleIds.IsSpecified) { await Discord.ApiClient.ModifyGuildMemberAsync(Guild.Id, Id, args).ConfigureAwait(false); - if (args.Deaf.IsSpecified) - IsDeaf = args.Deaf.Value; - if (args.Mute.IsSpecified) - IsMute = args.Mute.Value; if (args.Nickname.IsSpecified) Nickname = args.Nickname.Value ?? ""; if (args.RoleIds.IsSpecified) @@ -161,6 +144,8 @@ namespace Discord IGuild IGuildUser.Guild => Guild; IReadOnlyCollection IGuildUser.Roles => Roles; + bool IVoiceState.IsDeafened => false; + bool IVoiceState.IsMuted => false; bool IVoiceState.IsSelfDeafened => false; bool IVoiceState.IsSelfMuted => false; bool IVoiceState.IsSuppressed => false; diff --git a/src/Discord.Net/Entities/Users/IGuildUser.cs b/src/Discord.Net/Entities/Users/IGuildUser.cs index 280713d33..94728723e 100644 --- a/src/Discord.Net/Entities/Users/IGuildUser.cs +++ b/src/Discord.Net/Entities/Users/IGuildUser.cs @@ -8,10 +8,6 @@ namespace Discord /// A Guild-User pairing. public interface IGuildUser : IUpdateable, IUser, IVoiceState { - /// Returns true if the guild has deafened this user. - bool IsDeaf { get; } - /// Returns true if the guild has muted this user. - bool IsMute { get; } /// Gets when this user joined this guild. DateTimeOffset? JoinedAt { get; } /// Gets the nickname for this user. diff --git a/src/Discord.Net/Entities/Users/IVoiceState.cs b/src/Discord.Net/Entities/Users/IVoiceState.cs index 8bdd7436c..428601f2a 100644 --- a/src/Discord.Net/Entities/Users/IVoiceState.cs +++ b/src/Discord.Net/Entities/Users/IVoiceState.cs @@ -2,6 +2,10 @@ { public interface IVoiceState { + /// Returns true if the guild has deafened this user. + bool IsDeafened { get; } + /// Returns true if the guild has muted this user. + bool IsMuted { get; } /// Returns true if this user has marked themselves as deafened. bool IsSelfDeafened { get; } /// Returns true if this user has marked themselves as muted. diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs b/src/Discord.Net/Entities/WebSocket/CachedGuild.cs index a86557f02..2bd067da8 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs +++ b/src/Discord.Net/Entities/WebSocket/CachedGuild.cs @@ -204,7 +204,7 @@ namespace Discord public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary voiceStates = null) { var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel; - var voiceState = new VoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress); + var voiceState = new VoiceState(voiceChannel, model); (voiceStates ?? _voiceStates)[model.UserId] = voiceState; return voiceState; } diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs b/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs index 294752d64..86036d188 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs +++ b/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs @@ -3,17 +3,31 @@ using PresenceModel = Discord.API.Presence; namespace Discord { + //TODO: C#7 Candidate for record type + internal struct Presence : IPresence + { + public Game Game { get; } + public UserStatus Status { get; } + + public Presence(Game game, UserStatus status) + { + Game = game; + Status = status; + } + + public Presence Clone() => this; + } + internal class CachedGuildUser : GuildUser, ICachedUser { - private Game _game; - private UserStatus _status; + public Presence Presence { get; private set; } public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new CachedGuild Guild => base.Guild as CachedGuild; public new CachedGlobalUser User => base.User as CachedGlobalUser; - public override Game Game => _game; - public override UserStatus Status => _status; + public override Game Game => Presence.Game; + public override UserStatus Status => Presence.Status; public VoiceState? VoiceState => Guild.GetVoiceState(Id); public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; @@ -34,8 +48,8 @@ namespace Discord { base.Update(model, source); - _status = model.Status; - _game = model.Game != null ? new Game(model.Game) : (Game)null; + var game = model.Game != null ? new Game(model.Game) : null; + Presence = new Presence(game, model.Status); } public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser; diff --git a/src/Discord.Net/Entities/WebSocket/VoiceState.cs b/src/Discord.Net/Entities/WebSocket/VoiceState.cs index fc183a520..275108476 100644 --- a/src/Discord.Net/Entities/WebSocket/VoiceState.cs +++ b/src/Discord.Net/Entities/WebSocket/VoiceState.cs @@ -1,16 +1,20 @@ using System; +using Model = Discord.API.VoiceState; namespace Discord { + //TODO: C#7 Candidate for record type internal struct VoiceState : IVoiceState { [Flags] private enum Flags : byte { - None = 0x0, - Suppressed = 0x1, - SelfMuted = 0x2, - SelfDeafened = 0x4, + None = 0x00, + Suppressed = 0x01, + Muted = 0x02, + Deafened = 0x04, + SelfMuted = 0x08, + SelfDeafened = 0x10, } private readonly Flags _voiceStates; @@ -18,10 +22,14 @@ namespace Discord public CachedVoiceChannel VoiceChannel { get; } public string VoiceSessionId { get; } + public bool IsMuted => (_voiceStates & Flags.Muted) != 0; + public bool IsDeafened => (_voiceStates & Flags.Deafened) != 0; + public bool IsSuppressed => (_voiceStates & Flags.Suppressed) != 0; 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, Model model) + : this(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress) { } public VoiceState(CachedVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed) { VoiceChannel = voiceChannel; @@ -37,6 +45,8 @@ namespace Discord _voiceStates = voiceStates; } + public VoiceState Clone() => this; + IVoiceChannel IVoiceState.VoiceChannel => VoiceChannel; } }