| @@ -0,0 +1,12 @@ | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class Pan | |||
| { | |||
| [JsonProperty("left")] | |||
| public float Left { get; set; } | |||
| [JsonProperty("right")] | |||
| public float Right { get; set; } | |||
| } | |||
| } | |||
| @@ -1,7 +1,21 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class VoiceStateEvent | |||
| { | |||
| [JsonProperty("user")] | |||
| public User User { get; set; } | |||
| [JsonProperty("voice_state")] | |||
| public Optional<VoiceState> VoiceState { get; set; } | |||
| [JsonProperty("nick")] | |||
| public Optional<string> Nickname { get; set; } | |||
| [JsonProperty("volume")] | |||
| public Optional<int> Volume { get; set; } | |||
| [JsonProperty("mute")] | |||
| public Optional<bool> Mute { get; set; } | |||
| [JsonProperty("pan")] | |||
| public Optional<Pan> Pan { get; set; } | |||
| } | |||
| } | |||
| @@ -34,18 +34,39 @@ namespace Discord.Rpc | |||
| private readonly AsyncEvent<Func<Task>> _guildUpdatedEvent = new AsyncEvent<Func<Task>>(); | |||
| //Voice | |||
| public event Func<RpcVoiceState, Task> VoiceStateCreated | |||
| { | |||
| add { _voiceStateCreatedEvent.Add(value); } | |||
| remove { _voiceStateCreatedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<RpcVoiceState, Task>> _voiceStateCreatedEvent = new AsyncEvent<Func<RpcVoiceState, Task>>(); | |||
| public event Func<RpcVoiceState, Task> VoiceStateUpdated | |||
| { | |||
| add { _voiceStateUpdatedEvent.Add(value); } | |||
| remove { _voiceStateUpdatedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<RpcVoiceState, Task>> _voiceStateUpdatedEvent = new AsyncEvent<Func<RpcVoiceState, Task>>(); | |||
| public event Func<RpcVoiceState, Task> VoiceStateDeleted | |||
| { | |||
| add { _voiceStateDeletedEvent.Add(value); } | |||
| remove { _voiceStateDeletedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<RpcVoiceState, Task>> _voiceStateDeletedEvent = new AsyncEvent<Func<RpcVoiceState, Task>>(); | |||
| public event Func<ulong, Task> SpeakingStarted | |||
| { | |||
| add { _speakingStarted.Add(value); } | |||
| remove { _speakingStarted.Remove(value); } | |||
| add { _speakingStartedEvent.Add(value); } | |||
| remove { _speakingStartedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<ulong, Task>> _speakingStarted = new AsyncEvent<Func<ulong, Task>>(); | |||
| private readonly AsyncEvent<Func<ulong, Task>> _speakingStartedEvent = new AsyncEvent<Func<ulong, Task>>(); | |||
| public event Func<ulong, Task> SpeakingStopped | |||
| { | |||
| add { _speakingStopped.Add(value); } | |||
| remove { _speakingStopped.Remove(value); } | |||
| add { _speakingStoppedEvent.Add(value); } | |||
| remove { _speakingStoppedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<ulong, Task>> _speakingStopped = new AsyncEvent<Func<ulong, Task>>(); | |||
| private readonly AsyncEvent<Func<ulong, Task>> _speakingStoppedEvent = new AsyncEvent<Func<ulong, Task>>(); | |||
| //Messages | |||
| public event Func<RpcMessage, Task> MessageReceived | |||
| @@ -331,34 +331,40 @@ namespace Discord.Rpc | |||
| break; | |||
| //Voice | |||
| /*case "VOICE_STATE_CREATE": | |||
| case "VOICE_STATE_CREATE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_CREATE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<VoiceStateEvent>(_serializer); | |||
| var voiceState = RpcVoiceState.Create(this, data); | |||
| await _voiceStateUpdatedEvent.InvokeAsync().ConfigureAwait(false); | |||
| await _voiceStateCreatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | |||
| } | |||
| break; | |||
| case "VOICE_STATE_UPDATE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<VoiceStateEvent>(_serializer); | |||
| var voiceState = RpcVoiceState.Create(this, data); | |||
| await _voiceStateUpdatedEvent.InvokeAsync().ConfigureAwait(false); | |||
| await _voiceStateUpdatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | |||
| } | |||
| break; | |||
| case "VOICE_STATE_DELETE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_DELETE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<VoiceStateEvent>(_serializer); | |||
| var voiceState = RpcVoiceState.Create(this, data); | |||
| await _voiceStateUpdatedEvent.InvokeAsync().ConfigureAwait(false); | |||
| await _voiceStateDeletedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | |||
| } | |||
| break;*/ | |||
| break; | |||
| case "SPEAKING_START": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (SPEAKING_START)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<SpeakingEvent>(_serializer); | |||
| await _speakingStarted.InvokeAsync(data.UserId).ConfigureAwait(false); | |||
| await _speakingStartedEvent.InvokeAsync(data.UserId).ConfigureAwait(false); | |||
| } | |||
| break; | |||
| case "SPEAKING_STOP": | |||
| @@ -366,7 +372,7 @@ namespace Discord.Rpc | |||
| await _rpcLogger.DebugAsync("Received Dispatch (SPEAKING_STOP)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<SpeakingEvent>(_serializer); | |||
| await _speakingStopped.InvokeAsync(data.UserId).ConfigureAwait(false); | |||
| await _speakingStoppedEvent.InvokeAsync(data.UserId).ConfigureAwait(false); | |||
| } | |||
| break; | |||
| @@ -0,0 +1,20 @@ | |||
| using Model = Discord.API.Rpc.Pan; | |||
| namespace Discord.Rpc | |||
| { | |||
| public struct Pan | |||
| { | |||
| public float Left { get; } | |||
| public float Right { get; } | |||
| public Pan(float left, float right) | |||
| { | |||
| Left = left; | |||
| Right = right; | |||
| } | |||
| internal static Pan Create(Model model) | |||
| { | |||
| return new Pan(model.Left, model.Right); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,79 @@ | |||
| using System; | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.VoiceStateEvent; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcVoiceState : IVoiceState | |||
| { | |||
| [Flags] | |||
| private enum Flags : byte | |||
| { | |||
| Normal = 0x00, | |||
| Suppressed = 0x01, | |||
| Muted = 0x02, | |||
| Deafened = 0x04, | |||
| SelfMuted = 0x08, | |||
| SelfDeafened = 0x10, | |||
| } | |||
| private Flags _voiceStates; | |||
| public RpcUser User { get; } | |||
| public string Nickname { get; private set; } | |||
| public int Volume { get; private set; } | |||
| public bool IsMuted2 { get; private set; } | |||
| public Pan Pan { get; private set; } | |||
| 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; | |||
| internal RpcVoiceState(DiscordRpcClient discord, ulong userId) | |||
| { | |||
| User = new RpcUser(discord, userId); | |||
| } | |||
| internal static RpcVoiceState Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcVoiceState(discord, model.User.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal void Update(Model model) | |||
| { | |||
| if (model.VoiceState.IsSpecified) | |||
| { | |||
| Flags voiceStates = Flags.Normal; | |||
| if (model.VoiceState.Value.Mute) | |||
| voiceStates |= Flags.Muted; | |||
| if (model.VoiceState.Value.Deaf) | |||
| voiceStates |= Flags.Deafened; | |||
| if (model.VoiceState.Value.SelfMute) | |||
| voiceStates |= Flags.SelfMuted; | |||
| if (model.VoiceState.Value.SelfDeaf) | |||
| voiceStates |= Flags.SelfDeafened; | |||
| if (model.VoiceState.Value.Suppress) | |||
| voiceStates |= Flags.Suppressed; | |||
| _voiceStates = voiceStates; | |||
| } | |||
| User.Update(model.User); | |||
| if (model.Nickname.IsSpecified) | |||
| Nickname = model.Nickname.Value; | |||
| if (model.Volume.IsSpecified) | |||
| Volume = model.Volume.Value; | |||
| if (model.Mute.IsSpecified) | |||
| IsMuted2 = model.Mute.Value; | |||
| if (model.Pan.IsSpecified) | |||
| Pan = Pan.Create(model.Pan.Value); | |||
| } | |||
| public override string ToString() => User.ToString(); | |||
| internal string DebuggerDisplay => $"{User} ({_voiceStates})"; | |||
| string IVoiceState.VoiceSessionId { get { throw new NotSupportedException(); } } | |||
| IVoiceChannel IVoiceState.VoiceChannel { get { throw new NotSupportedException(); } } | |||
| } | |||
| } | |||