Бот не включает пользователя при настройке guildUserProperties.Отключить звук на false

#c# #discord.net

#c# #discord.net

Вопрос:

Я создал Discord-бота с помощью Discord.Сеть, которая наблюдает за несколькими голосовыми каналами из нескольких гильдий. Я слушаю UserVoiceStateUpdated событие, потому что всякий раз, когда пользователь присоединяется к наблюдаемому голосовому каналу, который отключен, этот пользователь должен быть отключен ботом. Всякий раз, когда пользователь покидает наблюдаемый голосовой канал, этот пользователь должен быть включен.

У меня есть кэш памяти, содержащий информацию обо всех наблюдаемых голосовых каналах. Каждый информационный объект предоставляет эту информацию

 public class ObservedVoiceChannelInfo
{
    public ulong VoiceChannelId { get; set; }
    public bool Muted { get; set; }
    public List<ulong> MutedUserIds { get; set; } = new List<ulong>();
}
 

Для части события я подумал о следующем:

  • Если пользователь покидает наблюдаемый голосовой канал, который находится в отключенном состоянии, этот пользователь должен быть отключен ботом
  • Если пользователь присоединяется к наблюдаемому голосовому каналу, который находится в отключенном состоянии, этот пользователь должен быть отключен ботом

По сути, я хочу добиться: если кто-то присоединяется к наблюдаемому отключенному голосовому каналу, отключите этого пользователя. Если этот пользователь покидает этот канал, включите его, если состояние было отключено.

Это моя текущая реализация ( observedVoiceChannelsCache это словарь кэша в памяти с наблюдаемыми голосовыми каналами)

     private async Task OnUserVoiceStateUpdated(SocketUser socketUser, SocketVoiceState oldSocketVoiceState,
        SocketVoiceState newSocketVoiceState)
    {
        SocketGuildUser socketGuildUser = socketUser as SocketGuildUser;

        if (newSocketVoiceState.IsMuted amp;amp;
            newSocketVoiceState.VoiceChannel == null amp;amp;
            _observedVoiceChannelsCache.TryGetValue(oldSocketVoiceState.VoiceChannel.Id,
                out ObservedVoiceChannelInfo oldObservedVoiceChannelInfo) amp;amp;
            oldObservedVoiceChannelInfo.Muted)
        {
            bool userRemovedFromMuteList = oldObservedVoiceChannelInfo.MutedUserIds.Remove(socketGuildUser.Id);

            if (userRemovedFromMuteList)
                await SetUserVoiceState(socketGuildUser, false);
        }
        else if (!newSocketVoiceState.IsMuted amp;amp;
                 newSocketVoiceState.VoiceChannel != null amp;amp;
                 _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id,
                     out ObservedVoiceChannelInfo newObservedVoiceChannelInfo) amp;amp;
                 newObservedVoiceChannelInfo.Muted)
        {
            await SetUserVoiceState(socketGuildUser, true);
            newObservedVoiceChannelInfo.MutedUserIds.Add(socketGuildUser.Id);
        }
    }

    private async Task SetUserVoiceState(SocketGuildUser socketGuildUser, bool muted)
    {
        await socketGuildUser.ModifyAsync(guildUserProperties => { guildUserProperties.Mute = muted; });
    }
 

Блок else, похоже, работает нормально (присоединяется к наблюдаемому отключенному каналу). Но первый блок if (оставляющий наблюдаемый отключенный канал) не работает. Пользователь удаляется из списка, но при вызове SetUserVoiceState с false пользователем бот не отключает его. Я могу воспроизвести это, присоединившись к наблюдаемому отключенному голосовому каналу, оставив его и присоединившись к другому голосовому каналу, который не наблюдается. Тогда я все еще отключен.

Кто-нибудь знает, чего здесь не хватает?

Комментарии:

1. Насколько мне известно, пользователь должен быть подключен к голосовому каналу, чтобы его можно было отключить / включить

2. вы думали о том, чтобы отключить пользователя, когда он присоединяется к каналу без отключения звука, или это по какой-то причине не сработает?

3. @Mikah ну, я думал об этом, но представляю пользователя, отключенного модератором за плохое поведение. Я думаю, этот пользователь должен оставаться отключенным

4. @Question3r хорошо, у меня появилась идея, что я работаю над сценарием, который решит проблему. Я добавлю пользователя в список, если он отключит звук сам или если он отключен администратором, и я не буду включать их, если они есть в списке.

Ответ №1:

примечание: переменные под важными комментариями должны быть инициализированы при запуске бота.

Скрипт работает, отслеживая отключенных пользователей и не отключает пользователей, которые были отключены администратором. Бот может отслеживать отключенных пользователей только в активном состоянии, поэтому вы можете включить функцию сохранения для списка SelfOrAdminMutedUsersIds или разработать способ получения этого списка из discord.

 public class ObservedVoiceChannelInfo
{
    public ulong VoiceChannelId { get; set; }
    public bool Muted { get; set; }
    public List<ulong> MutedUserIds { get; set; } = new List<ulong>();
}
public class ObservedGuildsMutingInfo
{
    public ulong GuildId { get; set; }
    public List<ulong> SelfOrAdminMutedUsersIds { get; set; }
}

//IMPORTANT: make sure to initialize on bot start:
public Dictionary<ulong, ObservedGuildsMutingInfo> _observedGuildsMutingInfoCache = new Dictionary<ulong, ObservedGuildsMutingInfo>();
//IMPORTANT: make sure to initialize on bot start:
public Dictionary<ulong, ObservedVoiceChannelInfo> _observedVoiceChannelsCache = new Dictionary<ulong, ObservedGuildsMutingInfo>();

private async Task OnUserVoiceStateUpdated(SocketUser socketUser, SocketVoiceState oldSocketVoiceState,
    SocketVoiceState newSocketVoiceState)
{
    SocketGuildUser socketGuildUser = socketUser as SocketGuildUser;
    
    if (!oldSocketVoiceState.IsMuted amp;amp; newSocketVoiceState.IsMuted amp;amp; 
        _observedGuildsMutingInfoCache.TryGetValue(newSocketVoiceState.VoiceChannel.Guild.Id, out ObservedGuildsMutingInfo newObservedMutinglInfo))
    {
        // a user was muted by someone
        if (_observedVoiceChannelsCache.TryGetValue(oldSocketVoiceState.VoiceChannel.Id, out ObservedVoiceChannelInfo oldObservedVoiceChannelInfo)amp;amp;
            !oldObservedVoiceChannelInfo.MutedUserIds.Contains(socketGuildUser.Id))
        {
            // the user was not muted by the bot
            // meaning that the user muted theirselfs or were muted by admin
            newObservedMutingInfo.SelfOrAdminMutedUsersIds.Add(socketGuildUser.Id);
        }
    }
    else if (!oldSocketVoiceState.IsMuted amp;amp; newSocketVoiceState.IsMuted amp;amp; 
        _observedGuildsMutingInfoCache.TryGetValue(newSocketVoiceState.VoiceChannel.Guild.Id, out ObservedGuildsMutingInfo newObservedMutinglInfo))
    {
        // a user was un-muted by someone
        newObservedMutingInfo.SelfOrAdminMutedUsersIds.Remove(socketGuildUser.Id);
    }
    else if (!newSocketVoiceState.IsMuted amp;amp;
        newSocketVoiceState.VoiceChannel != null amp;amp;
        _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id,
        out ObservedVoiceChannelInfo newObservedVoiceChannelInfo) amp;amp;
        !newObservedVoiceChannelInfo.Muted)
    {
        // user has joined a un-muted channel
        if(_observedGuildsMutingInfoCache.TryGetValue(newSocketVoiceState.VoiceChannel.Guild.Id, out ObservedGuildsMutingInfo newObservedGuildsMutingInfo)amp;amp;
            !newObservedGuildsMutingInfo.SelfOrAdminMutedUsersIds.Contains(socketGuildUser.Id))
        {
            await SetUserVoiceState(socketGuildUser, false);
        }
    }
    else if (newSocketVoiceState.IsMuted amp;amp;
        newSocketVoiceState.VoiceChannel == null amp;amp;
        _observedVoiceChannelsCache.TryGetValue(oldSocketVoiceState.VoiceChannel.Id,
            out ObservedVoiceChannelInfo oldObservedVoiceChannelInfo) amp;amp;
        oldObservedVoiceChannelInfo.Muted)
    {
        oldObservedVoiceChannelInfo.MutedUserIds.Remove(socketGuildUser.Id);
    }
    else if (!newSocketVoiceState.IsMuted amp;amp;
         newSocketVoiceState.VoiceChannel != null amp;amp;
         _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id,
             out ObservedVoiceChannelInfo newObservedVoiceChannelInfo) amp;amp;
             newObservedVoiceChannelInfo.Muted)
    {
        await SetUserVoiceState(socketGuildUser, true);
        newObservedVoiceChannelInfo.MutedUserIds.Add(socketGuildUser.Id);
    }
}

private async Task SetUserVoiceState(SocketGuildUser socketGuildUser, bool muted)
{
    await socketGuildUser.ModifyAsync(guildUserProperties => { guildUserProperties.Mute = muted; });
}
 

Я надеялся, что это поможет.