@@ -0,0 +1,190 @@ | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public partial class DiscordSocketClient | |||
{ | |||
//General | |||
public event Func<Task> Connected | |||
{ | |||
add { _connectedEvent.Add(value); } | |||
remove { _connectedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<Task>> _connectedEvent = new AsyncEvent<Func<Task>>(); | |||
public event Func<Task> Disconnected | |||
{ | |||
add { _disconnectedEvent.Add(value); } | |||
remove { _disconnectedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<Task>> _disconnectedEvent = new AsyncEvent<Func<Task>>(); | |||
public event Func<Task> Ready | |||
{ | |||
add { _readyEvent.Add(value); } | |||
remove { _readyEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<Task>> _readyEvent = new AsyncEvent<Func<Task>>(); | |||
public event Func<int, int, Task> LatencyUpdated | |||
{ | |||
add { _latencyUpdatedEvent.Add(value); } | |||
remove { _latencyUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<int, int, Task>> _latencyUpdatedEvent = new AsyncEvent<Func<int, int, Task>>(); | |||
//Channels | |||
public event Func<IChannel, Task> ChannelCreated | |||
{ | |||
add { _channelCreatedEvent.Add(value); } | |||
remove { _channelCreatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IChannel, Task>> _channelCreatedEvent = new AsyncEvent<Func<IChannel, Task>>(); | |||
public event Func<IChannel, Task> ChannelDestroyed | |||
{ | |||
add { _channelDestroyedEvent.Add(value); } | |||
remove { _channelDestroyedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IChannel, Task>> _channelDestroyedEvent = new AsyncEvent<Func<IChannel, Task>>(); | |||
public event Func<IChannel, IChannel, Task> ChannelUpdated | |||
{ | |||
add { _channelUpdatedEvent.Add(value); } | |||
remove { _channelUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IChannel, IChannel, Task>> _channelUpdatedEvent = new AsyncEvent<Func<IChannel, IChannel, Task>>(); | |||
//Messages | |||
public event Func<IMessage, Task> MessageReceived | |||
{ | |||
add { _messageReceivedEvent.Add(value); } | |||
remove { _messageReceivedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IMessage, Task>> _messageReceivedEvent = new AsyncEvent<Func<IMessage, Task>>(); | |||
public event Func<ulong, Optional<IMessage>, Task> MessageDeleted | |||
{ | |||
add { _messageDeletedEvent.Add(value); } | |||
remove { _messageDeletedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<ulong, Optional<IMessage>, Task>> _messageDeletedEvent = new AsyncEvent<Func<ulong, Optional<IMessage>, Task>>(); | |||
public event Func<Optional<IMessage>, IMessage, Task> MessageUpdated | |||
{ | |||
add { _messageUpdatedEvent.Add(value); } | |||
remove { _messageUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<Optional<IMessage>, IMessage, Task>> _messageUpdatedEvent = new AsyncEvent<Func<Optional<IMessage>, IMessage, Task>>(); | |||
//Roles | |||
public event Func<IRole, Task> RoleCreated | |||
{ | |||
add { _roleCreatedEvent.Add(value); } | |||
remove { _roleCreatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IRole, Task>> _roleCreatedEvent = new AsyncEvent<Func<IRole, Task>>(); | |||
public event Func<IRole, Task> RoleDeleted | |||
{ | |||
add { _roleDeletedEvent.Add(value); } | |||
remove { _roleDeletedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IRole, Task>> _roleDeletedEvent = new AsyncEvent<Func<IRole, Task>>(); | |||
public event Func<IRole, IRole, Task> RoleUpdated | |||
{ | |||
add { _roleUpdatedEvent.Add(value); } | |||
remove { _roleUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IRole, IRole, Task>> _roleUpdatedEvent = new AsyncEvent<Func<IRole, IRole, Task>>(); | |||
//Guilds | |||
public event Func<IGuild, Task> JoinedGuild | |||
{ | |||
add { _joinedGuildEvent.Add(value); } | |||
remove { _joinedGuildEvent.Remove(value); } | |||
} | |||
private AsyncEvent<Func<IGuild, Task>> _joinedGuildEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> LeftGuild | |||
{ | |||
add { _leftGuildEvent.Add(value); } | |||
remove { _leftGuildEvent.Remove(value); } | |||
} | |||
private AsyncEvent<Func<IGuild, Task>> _leftGuildEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> GuildAvailable | |||
{ | |||
add { _guildAvailableEvent.Add(value); } | |||
remove { _guildAvailableEvent.Remove(value); } | |||
} | |||
private AsyncEvent<Func<IGuild, Task>> _guildAvailableEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> GuildUnavailable | |||
{ | |||
add { _guildUnavailableEvent.Add(value); } | |||
remove { _guildUnavailableEvent.Remove(value); } | |||
} | |||
private AsyncEvent<Func<IGuild, Task>> _guildUnavailableEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> GuildDownloadedMembers | |||
{ | |||
add { _guildDownloadedMembersEvent.Add(value); } | |||
remove { _guildDownloadedMembersEvent.Remove(value); } | |||
} | |||
private AsyncEvent<Func<IGuild, Task>> _guildDownloadedMembersEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, IGuild, Task> GuildUpdated | |||
{ | |||
add { _guildUpdatedEvent.Add(value); } | |||
remove { _guildUpdatedEvent.Remove(value); } | |||
} | |||
private AsyncEvent<Func<IGuild, IGuild, Task>> _guildUpdatedEvent = new AsyncEvent<Func<IGuild, IGuild, Task>>(); | |||
//Users | |||
public event Func<IGuildUser, Task> UserJoined | |||
{ | |||
add { _userJoinedEvent.Add(value); } | |||
remove { _userJoinedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IGuildUser, Task>> _userJoinedEvent = new AsyncEvent<Func<IGuildUser, Task>>(); | |||
public event Func<IGuildUser, Task> UserLeft | |||
{ | |||
add { _userLeftEvent.Add(value); } | |||
remove { _userLeftEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IGuildUser, Task>> _userLeftEvent = new AsyncEvent<Func<IGuildUser, Task>>(); | |||
public event Func<IUser, IGuild, Task> UserBanned | |||
{ | |||
add { _userBannedEvent.Add(value); } | |||
remove { _userBannedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IUser, IGuild, Task>> _userBannedEvent = new AsyncEvent<Func<IUser, IGuild, Task>>(); | |||
public event Func<IUser, IGuild, Task> UserUnbanned | |||
{ | |||
add { _userUnbannedEvent.Add(value); } | |||
remove { _userUnbannedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IUser, IGuild, Task>> _userUnbannedEvent = new AsyncEvent<Func<IUser, IGuild, Task>>(); | |||
public event Func<IGuildUser, IGuildUser, Task> UserUpdated | |||
{ | |||
add { _userUpdatedEvent.Add(value); } | |||
remove { _userUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IGuildUser, IGuildUser, Task>> _userUpdatedEvent = new AsyncEvent<Func<IGuildUser, IGuildUser, Task>>(); | |||
public event Func<IGuildUser, IPresence, IPresence, Task> UserPresenceUpdated | |||
{ | |||
add { _userPresenceUpdatedEvent.Add(value); } | |||
remove { _userPresenceUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IGuildUser, IPresence, IPresence, Task>> _userPresenceUpdatedEvent = new AsyncEvent<Func<IGuildUser, IPresence, IPresence, Task>>(); | |||
public event Func<IGuildUser, IVoiceState, IVoiceState, Task> UserVoiceStateUpdated | |||
{ | |||
add { _userVoiceStateUpdatedEvent.Add(value); } | |||
remove { _userVoiceStateUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IGuildUser, IVoiceState, IVoiceState, Task>> _userVoiceStateUpdatedEvent = new AsyncEvent<Func<IGuildUser, IVoiceState, IVoiceState, Task>>(); | |||
public event Func<ISelfUser, ISelfUser, Task> CurrentUserUpdated | |||
{ | |||
add { _selfUpdatedEvent.Add(value); } | |||
remove { _selfUpdatedEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<ISelfUser, ISelfUser, Task>> _selfUpdatedEvent = new AsyncEvent<Func<ISelfUser, ISelfUser, Task>>(); | |||
public event Func<IUser, IChannel, Task> UserIsTyping | |||
{ | |||
add { _userIsTypingEvent.Add(value); } | |||
remove { _userIsTypingEvent.Remove(value); } | |||
} | |||
private readonly AsyncEvent<Func<IUser, IChannel, Task>> _userIsTypingEvent = new AsyncEvent<Func<IUser, IChannel, Task>>(); | |||
//TODO: Add PresenceUpdated? VoiceStateUpdated?, VoiceConnected, VoiceDisconnected; | |||
} | |||
} |
@@ -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<Task> Connected { add { _connectedEvent.Add(value); } remove { _connectedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<Task>> _connectedEvent = new AsyncEvent<Func<Task>>(); | |||
public event Func<Task> Disconnected { add { _disconnectedEvent.Add(value); } remove { _disconnectedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<Task>> _disconnectedEvent = new AsyncEvent<Func<Task>>(); | |||
public event Func<Task> Ready { add { _readyEvent.Add(value); } remove { _readyEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<Task>> _readyEvent = new AsyncEvent<Func<Task>>(); | |||
public event Func<int, int, Task> LatencyUpdated { add { _latencyUpdatedEvent.Add(value); } remove { _latencyUpdatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<int, int, Task>> _latencyUpdatedEvent = new AsyncEvent<Func<int, int, Task>>(); | |||
//Channels | |||
public event Func<IChannel, Task> ChannelCreated { add { _channelCreatedEvent.Add(value); } remove { _channelCreatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IChannel, Task>> _channelCreatedEvent = new AsyncEvent<Func<IChannel, Task>>(); | |||
public event Func<IChannel, Task> ChannelDestroyed { add { _channelDestroyedEvent.Add(value); } remove { _channelDestroyedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IChannel, Task>> _channelDestroyedEvent = new AsyncEvent<Func<IChannel, Task>>(); | |||
public event Func<IChannel, IChannel, Task> ChannelUpdated { add { _channelUpdatedEvent.Add(value); } remove { _channelUpdatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IChannel, IChannel, Task>> _channelUpdatedEvent = new AsyncEvent<Func<IChannel, IChannel, Task>>(); | |||
//Messages | |||
public event Func<IMessage, Task> MessageReceived { add { _messageReceivedEvent.Add(value); } remove { _messageReceivedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IMessage, Task>> _messageReceivedEvent = new AsyncEvent<Func<IMessage, Task>>(); | |||
public event Func<ulong, Optional<IMessage>, Task> MessageDeleted { add { _messageDeletedEvent.Add(value); } remove { _messageDeletedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<ulong, Optional<IMessage>, Task>> _messageDeletedEvent = new AsyncEvent<Func<ulong, Optional<IMessage>, Task>>(); | |||
public event Func<Optional<IMessage>, IMessage, Task> MessageUpdated { add { _messageUpdatedEvent.Add(value); } remove { _messageUpdatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<Optional<IMessage>, IMessage, Task>> _messageUpdatedEvent = new AsyncEvent<Func<Optional<IMessage>, IMessage, Task>>(); | |||
//Roles | |||
public event Func<IRole, Task> RoleCreated { add { _roleCreatedEvent.Add(value); } remove { _roleCreatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IRole, Task>> _roleCreatedEvent = new AsyncEvent<Func<IRole, Task>>(); | |||
public event Func<IRole, Task> RoleDeleted { add { _roleDeletedEvent.Add(value); } remove { _roleDeletedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IRole, Task>> _roleDeletedEvent = new AsyncEvent<Func<IRole, Task>>(); | |||
public event Func<IRole, IRole, Task> RoleUpdated { add { _roleUpdatedEvent.Add(value); } remove { _roleUpdatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IRole, IRole, Task>> _roleUpdatedEvent = new AsyncEvent<Func<IRole, IRole, Task>>(); | |||
//Guilds | |||
public event Func<IGuild, Task> JoinedGuild { add { _joinedGuildEvent.Add(value); } remove { _joinedGuildEvent.Remove(value); } } | |||
private AsyncEvent<Func<IGuild, Task>> _joinedGuildEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> LeftGuild { add { _leftGuildEvent.Add(value); } remove { _leftGuildEvent.Remove(value); } } | |||
private AsyncEvent<Func<IGuild, Task>> _leftGuildEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> GuildAvailable { add { _guildAvailableEvent.Add(value); } remove { _guildAvailableEvent.Remove(value); } } | |||
private AsyncEvent<Func<IGuild, Task>> _guildAvailableEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> GuildUnavailable { add { _guildUnavailableEvent.Add(value); } remove { _guildUnavailableEvent.Remove(value); } } | |||
private AsyncEvent<Func<IGuild, Task>> _guildUnavailableEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, Task> GuildDownloadedMembers { add { _guildDownloadedMembersEvent.Add(value); } remove { _guildDownloadedMembersEvent.Remove(value); } } | |||
private AsyncEvent<Func<IGuild, Task>> _guildDownloadedMembersEvent = new AsyncEvent<Func<IGuild, Task>>(); | |||
public event Func<IGuild, IGuild, Task> GuildUpdated { add { _guildUpdatedEvent.Add(value); } remove { _guildUpdatedEvent.Remove(value); } } | |||
private AsyncEvent<Func<IGuild, IGuild, Task>> _guildUpdatedEvent = new AsyncEvent<Func<IGuild, IGuild, Task>>(); | |||
//Users | |||
public event Func<IGuildUser, Task> UserJoined { add { _userJoinedEvent.Add(value); } remove { _userJoinedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IGuildUser, Task>> _userJoinedEvent = new AsyncEvent<Func<IGuildUser, Task>>(); | |||
public event Func<IGuildUser, Task> UserLeft { add { _userLeftEvent.Add(value); } remove { _userLeftEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IGuildUser, Task>> _userLeftEvent = new AsyncEvent<Func<IGuildUser, Task>>(); | |||
public event Func<IUser, IGuild, Task> UserBanned { add { _userBannedEvent.Add(value); } remove { _userBannedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IUser, IGuild, Task>> _userBannedEvent = new AsyncEvent<Func<IUser, IGuild, Task>>(); | |||
public event Func<IUser, IGuild, Task> UserUnbanned { add { _userUnbannedEvent.Add(value); } remove { _userUnbannedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IUser, IGuild, Task>> _userUnbannedEvent = new AsyncEvent<Func<IUser, IGuild, Task>>(); | |||
public event Func<Optional<IGuildUser>, IGuildUser, Task> UserUpdated { add { _userUpdatedEvent.Add(value); } remove { _userUpdatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<Optional<IGuildUser>, IGuildUser, Task>> _userUpdatedEvent = new AsyncEvent<Func<Optional<IGuildUser>, IGuildUser, Task>>(); | |||
public event Func<ISelfUser, ISelfUser, Task> CurrentUserUpdated { add { _selfUpdatedEvent.Add(value); } remove { _selfUpdatedEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<ISelfUser, ISelfUser, Task>> _selfUpdatedEvent = new AsyncEvent<Func<ISelfUser, ISelfUser, Task>>(); | |||
public event Func<IUser, IChannel, Task> UserIsTyping { add { _userIsTypingEvent.Add(value); } remove { _userIsTypingEvent.Remove(value); } } | |||
private readonly AsyncEvent<Func<IUser, IChannel, Task>> _userIsTypingEvent = new AsyncEvent<Func<IUser, IChannel, Task>>(); | |||
//TODO: Add PresenceUpdated? VoiceStateUpdated?, VoiceConnected, VoiceDisconnected; | |||
private readonly ConcurrentQueue<ulong> _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<IGuildUser>(), 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<API.User>(_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<API.User>(_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); | |||
@@ -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<Role>(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<IRole> IGuildUser.Roles => Roles; | |||
bool IVoiceState.IsDeafened => false; | |||
bool IVoiceState.IsMuted => false; | |||
bool IVoiceState.IsSelfDeafened => false; | |||
bool IVoiceState.IsSelfMuted => false; | |||
bool IVoiceState.IsSuppressed => false; | |||
@@ -8,10 +8,6 @@ namespace Discord | |||
/// <summary> A Guild-User pairing. </summary> | |||
public interface IGuildUser : IUpdateable, IUser, IVoiceState | |||
{ | |||
/// <summary> Returns true if the guild has deafened this user. </summary> | |||
bool IsDeaf { get; } | |||
/// <summary> Returns true if the guild has muted this user. </summary> | |||
bool IsMute { get; } | |||
/// <summary> Gets when this user joined this guild. </summary> | |||
DateTimeOffset? JoinedAt { get; } | |||
/// <summary> Gets the nickname for this user. </summary> | |||
@@ -2,6 +2,10 @@ | |||
{ | |||
public interface IVoiceState | |||
{ | |||
/// <summary> Returns true if the guild has deafened this user. </summary> | |||
bool IsDeafened { get; } | |||
/// <summary> Returns true if the guild has muted this user. </summary> | |||
bool IsMuted { get; } | |||
/// <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> | |||
@@ -204,7 +204,7 @@ namespace Discord | |||
public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> 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; | |||
} | |||
@@ -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; | |||
@@ -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; | |||
} | |||
} |