Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bot doesn't unmute user when setting guildUserProperties.Mute to false

Tags:

c#

discord.net

I created a Discord bot using Discord.Net which is observing multiple voice channels from multiple guilds. I'm listening for the UserVoiceStateUpdated event because whenever a user joins an observed voice channel which is muted that user should get muted by the bot. Whenever the user leaves an observed voice channel that user should get unmuted.

I have a memory cache holding information about all observed voice channels. Each info object provides these information

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

For the event part I thought about the following:

  • If a user leaves an observed voice channel which has a muted state that user should get unmuted by the bot
  • If a user joins an observed voice channel which has a muted state that user should get muted by the bot

Basically what I want to achieve is: If someone joins an observed muted voice channel mute that user. If that user leaves this channel unmute him if the state was on mute.

This is my current implementation (observedVoiceChannelsCache is the in memory cache dictionary with observed voice channels)

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

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

            if (userRemovedFromMuteList)
                await SetUserVoiceState(socketGuildUser, false);
        }
        else if (!newSocketVoiceState.IsMuted &&
                 newSocketVoiceState.VoiceChannel != null &&
                 _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id,
                     out ObservedVoiceChannelInfo newObservedVoiceChannelInfo) &&
                 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; });
    }

The else block seems to work fine (joining an observed muted channel). But the first if block (leaving an observed muted channel) doesn't work. The user gets removed from the list but when when calling SetUserVoiceState with false the user doesn't get unmuted by the bot. I can reproduce it by joining an observed muted voice channel, leaving it and joining another voice channel that is not observed. I'm still muted then.

Does someone know what's missing here?

like image 239
Question3r Avatar asked Nov 07 '22 03:11

Question3r


1 Answers

note: the variables under the important comments need to be initialized on bot start.

The script works by keeping track of muted users and does not un-mute users that have been muted by an admin. The bot can only keep track of muted users when active, so you may want to include a save function for the SelfOrAdminMutedUsersIds list or develop a way to receive that list from 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 && newSocketVoiceState.IsMuted && 
        _observedGuildsMutingInfoCache.TryGetValue(newSocketVoiceState.VoiceChannel.Guild.Id, out ObservedGuildsMutingInfo newObservedMutinglInfo))
    {
        // a user was muted by someone
        if (_observedVoiceChannelsCache.TryGetValue(oldSocketVoiceState.VoiceChannel.Id, out ObservedVoiceChannelInfo oldObservedVoiceChannelInfo)&&
            !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 && newSocketVoiceState.IsMuted && 
        _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 &&
        newSocketVoiceState.VoiceChannel != null &&
        _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id,
        out ObservedVoiceChannelInfo newObservedVoiceChannelInfo) &&
        !newObservedVoiceChannelInfo.Muted)
    {
        // user has joined a un-muted channel
        if(_observedGuildsMutingInfoCache.TryGetValue(newSocketVoiceState.VoiceChannel.Guild.Id, out ObservedGuildsMutingInfo newObservedGuildsMutingInfo)&&
            !newObservedGuildsMutingInfo.SelfOrAdminMutedUsersIds.Contains(socketGuildUser.Id))
        {
            await SetUserVoiceState(socketGuildUser, false);
        }
    }
    else if (newSocketVoiceState.IsMuted &&
        newSocketVoiceState.VoiceChannel == null &&
        _observedVoiceChannelsCache.TryGetValue(oldSocketVoiceState.VoiceChannel.Id,
            out ObservedVoiceChannelInfo oldObservedVoiceChannelInfo) &&
        oldObservedVoiceChannelInfo.Muted)
    {
        oldObservedVoiceChannelInfo.MutedUserIds.Remove(socketGuildUser.Id);
    }
    else if (!newSocketVoiceState.IsMuted &&
         newSocketVoiceState.VoiceChannel != null &&
         _observedVoiceChannelsCache.TryGetValue(newSocketVoiceState.VoiceChannel.Id,
             out ObservedVoiceChannelInfo newObservedVoiceChannelInfo) &&
             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; });
}

I hoped this helps.

like image 112
Mikah Avatar answered Nov 15 '22 07:11

Mikah