#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; });
}
Я надеялся, что это поможет.