如何确定用户是否加入/切换/离开语音频道?

时间:2021-03-07 16:15:06

标签: c# discord.net

我正在使用 Discord.Net 并观察多个语音频道。如果这些语音通道处于静音状态,由机器人设置(不是通过权限),则该语音通道中的用户也应该被静音。

简单地从语音频道中删除发言权限不会立即影响人们,如您所见

https://support.discord.com/hc/en-us/community/posts/360052856033-Directly-affect-people-in-channels-on-permission-changes

如果他们离开,他们应该被取消静音。

所以这个包含所有必需的信息

public sealed class ObservedVoiceChannel
{
    public ulong VoiceChannelId { get; set; }
    public bool IsMuted { get; set; }
    // ... other information go here ...
}

我有一个服务保存所有观察到的语音频道

public sealed class ObservedVoiceChannelsCache : Dictionary<ulong, ObservedVoiceChannel>
{
}

因为只有一个 UserVoiceStateUpdated 事件,所以我想出了以下代码。

经过一些测试,我认为这段代码对我来说很好用。虽然我知道 if 语句可以通过“或”运算符提高可读性,但我会在解决最后一个问题后进行改进。

离开观察到的静音语音频道时,请参阅评论

<块引用>

// 用户离开观察到的静音语音通道

用户不会被机器人取消静音。有时,当加入和离开足够快时,处理程序会抛出异常

<块引用>

服务器响应错误 400:BadRequest

<块引用>

在 Discord.Net.Queue.RequestBucket.SendAsync(RestRequest 请求)
在 Discord.Net.Queue.RequestQueue.SendAsync(RestRequest request) 在 Discord.API.DiscordRestApiClient.SendInternalAsync(字符串方法, 字符串端点,RestRequest 请求)在 Discord.API.DiscordRestApiClient.SendJsonAsync(字符串方法,字符串 端点、对象负载、BucketId bucketId、ClientBucketType clientBucket、RequestOptions 选项)在 Discord.API.DiscordRestApiClient.ModifyGuildMemberAsync(UInt64 guildId, UInt64 userId, ModifyGuildMemberParams args, RequestOptions 选项)在 Discord.Rest.UserHelper.ModifyAsync(IGuildUser 用户, BaseDiscordClient 客户端,Action`1 func,RequestOptions 选项)在 ...OnUserVoiceStateUpdated(SocketUser socketUser, SocketVoiceState oldSocketVoiceState, SocketVoiceState newSocketVoiceState) 中 //.../UserVoiceStateUpdatedEventHandler.cs:line 52

这是我目前使用的代码

public sealed class UserVoiceStateUpdatedEventHandler
{
    private readonly ObservedVoiceChannelsCache _observedVoiceChannelsCache;
    
    public UserVoiceStateUpdatedEventHandler(ObservedVoiceChannelsCache observedVoiceChannelsCache)
    {
        _observedVoiceChannelsCache = observedVoiceChannelsCache;
    }
    
    public async Task OnUserVoiceStateUpdated(
        SocketUser socketUser, 
        SocketVoiceState oldSocketVoiceState,
        SocketVoiceState newSocketVoiceState)
    {
        if (socketUser is SocketGuildUser socketGuildUser)
        {
            bool userIsMuted = socketGuildUser.VoiceState?.IsMuted == true;
            bool userIsNotOffline = socketGuildUser.Status != UserStatus.Offline;
            
            // user left observed muted voice channel
            if (oldSocketVoiceState.VoiceChannel != null && 
                newSocketVoiceState.VoiceChannel == null &&
                _observedVoiceChannelsCache.TryGetValue(oldSocketVoiceState.VoiceChannel.Id, out ObservedVoiceChannel observedLeftVoiceChannel) &&
                observedLeftVoiceChannel.IsMuted &&
                userIsMuted &&
                userIsNotOffline
                )
            {
                await SetUserMuteState(socketGuildUser, false);
            }
            // user joined observed muted voice channel
            else if (oldSocketVoiceState.VoiceChannel == null && 
                     newSocketVoiceState.VoiceChannel != null &&
                     _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id, out ObservedVoiceChannel observedJoinedVoiceChannel) &&
                     observedJoinedVoiceChannel.IsMuted &&
                     !userIsMuted &&
                     userIsNotOffline)
            {
                await SetUserMuteState(socketGuildUser, true);
            }
            // user changed voice channels
            else if (oldSocketVoiceState.VoiceChannel != null && 
                     newSocketVoiceState.VoiceChannel != null &&
                     userIsNotOffline)
            {
                bool oldVoiceChannelObserved = _observedVoiceChannelsCache.TryGetValue(
                    oldSocketVoiceState.VoiceChannel.Id, out ObservedVoiceChannel oldObservedVoiceChannel);
                
                bool newVoiceChannelObserved = _observedVoiceChannelsCache.TryGetValue(
                    newSocketVoiceState.VoiceChannel.Id, out ObservedVoiceChannel newObservedVoiceChannel);

                // user moved from observed muted voice channel to unobserved voice channel
                if (oldVoiceChannelObserved && 
                    !newVoiceChannelObserved &&
                    oldObservedVoiceChannel.IsMuted &&
                    userIsMuted)
                {
                    await SetUserMuteState(socketGuildUser, false);
                }
                // user moved from unobserved voice channel to observed muted voice channel
                else if (!oldVoiceChannelObserved && 
                         newVoiceChannelObserved &&
                         newObservedVoiceChannel.IsMuted &&
                         !userIsMuted)
                {
                    await SetUserMuteState(socketGuildUser, true);
                }
                // both voice channels are observed
                else if (oldVoiceChannelObserved && newVoiceChannelObserved)
                {
                    // user moved from muted to unmuted voice channel
                    if (oldObservedVoiceChannel.IsMuted && 
                        !newObservedVoiceChannel.IsMuted &&
                        userIsMuted)
                    {
                        await SetUserMuteState(socketGuildUser, false);
                    }
                    // user moved from unmuted to muted voice channel
                    else if (!oldObservedVoiceChannel.IsMuted && 
                             newObservedVoiceChannel.IsMuted && 
                             !userIsMuted)
                    {
                        await SetUserMuteState(socketGuildUser, true);
                    }
                    // user moved from muted to muted voice channel
                    else if (oldObservedVoiceChannel.IsMuted && 
                             newObservedVoiceChannel.IsMuted && 
                             !userIsMuted)
                    {
                        await SetUserMuteState(socketGuildUser, true);
                    }
                }
            }
        }
    }

    private Task SetUserMuteState(SocketGuildUser socketGuildUser, bool muteUser)
        => socketGuildUser.ModifyAsync(guildUserProperties => guildUserProperties.Mute = muteUser);
}

我想知道如何将离开观察到的静音语音频道的用户取消静音。

我发现这里有这条线

bool userIsMuted = socketGuildUser.VoiceState?.IsMuted == true;

离开语音通道后返回false,因为语音状态为空。所以似乎没有办法检查用户再次加入时是否会被静音。

1 个答案:

答案 0 :(得分:0)

确定某人是加入、移动还是离开语音频道的方法是分别查看 SocketVoiceState oldSocketVoiceStateSocketVoiceState newSocketVoiceState 参数的 VoiceChannel 属性。 (oldSocketVoiceState.VoiceChannel -> newSocketVoiceState.VoiceChannel 对于以下示例):

  • 未连接进入新的语音通道(空 -> 通道 A)
  • 在语音频道之间切换(频道 A -> 频道 B)
  • 从语音通道断开连接(通道 B -> null)

要将加入语音频道的人静音,然后在他们断开连接后取消静音,您可以编写以下内容:

public async Task LogUserVoiceStateUpdatedAsync(SocketUser user, SocketVoiceState curVoiceState,
    SocketVoiceState nextVoiceState)
{
    if (user is not SocketGuildUser guildUser)
    {
        // They aren't a guild user, so we can't do anything to them.
        return;
    }
    
    // Note, you should make a method for the two switches below as in 
    // reality you're only changing one true/false flag depending on 
    // the voice states.
    
    // The user is leaving the voice channel.
    if (curVoiceState.VoiceChannel != null && nextVoiceState.VoiceChannel == null)
    {
        // Unmute the user.
        try
        {
            // Surround in try-catch in the event we lack permissions.
            await guildUser.ModifyAsync(x => x.Mute = false);
        }
        catch (Exception e)
        {
            // Will ALWAYS throw 400 bad request. I don't exactly know why, 
            // but it has to do with the modification being done after the user leaves the voice channel.
            
            // The warning can be safely be ignored.
            // _logger.LogWarning(e, $"Failed to unmute user in guild {guildUser.Guild.Id}.");
        }
    }
    else if (curVoiceState.VoiceChannel == null && nextVoiceState.VoiceChannel != null)
    {
        // Mute the user.
        try
        {
            // Surround in try-catch in the event we lack permissions.
            await guildUser.ModifyAsync(x => x.Mute = true);
        }
        catch (Exception e)
        {
            _logger.LogWarning(e, $"Failed to mute user in guild {guildUser.Guild.Id}.");
        }
    }
}
相关问题