Search code examples
javadiscord-jda

Can't display the amount of online users on Discord through bot activity


I'm coding a discord bot using JDA and I'm having a tough time trying to figure out a way to show in the bot's activity section the number of online users in a server.

This is my main bot class:

public DiscordBot() throws LoginException {

        config = Dotenv.configure().load();
        String token = config.get("TOKENDISCORD");
        eventListener = new BotEventListener();
        eventListener.addOnlineStatusChangeListener(event -> {
            int onlineMembers = eventListener.getQuantityOnlineMembers();
        });

  bot = JDABuilder.createDefault(token,
                        GatewayIntent.GUILD_MEMBERS,
                        GatewayIntent.GUILD_MESSAGES,
                        GatewayIntent.GUILD_PRESENCES,
                        GatewayIntent.GUILD_VOICE_STATES
                )
                .setMemberCachePolicy(MemberCachePolicy.ALL)
                .disableCache(EnumSet.of(
                        CacheFlag.CLIENT_STATUS,
                        CacheFlag.ACTIVITY,
                        CacheFlag.EMOTE
                ))
                .setChunkingFilter(ChunkingFilter.ALL)
                .enableCache(EnumSet.of(
                        CacheFlag.ONLINE_STATUS
                ))
                .setActivity(Activity.listening(new CustomActivity(eventListener).getName()))
                .setMemberCachePolicy(MemberCachePolicy.VOICE)
                .addEventListeners(eventListener)
                .addEventListeners(new BotCommands())
                .enableCache(CacheFlag.VOICE_STATE)
                .build();
    }

Event listener class:

//Triggering observer whenever a user is online or offline
    @Override
    public void onUserUpdateOnlineStatus(UserUpdateOnlineStatusEvent event) {
        System.out.println("test 1");
        onlineStatusEvent = event;
        int onlineMembers = getQuantityOnlineMembers();
        for (Consumer<Integer> listener : onlineStatusChangeListeners) {
            listener.accept(onlineMembers);
        }
    }

//Evaluating user amount
    public int getQuantityOnlineMembers() {
        System.out.println("test 2");
        if (onlineStatusEvent == null) {
            return 0;
        }
        System.out.println("test 3");
        List<Member> members = onlineStatusEvent.getGuild().getMembers();
        int onlineMembers = 0;
        for (Member member : members) {
            if (member.getOnlineStatus() == OnlineStatus.ONLINE) {
                onlineMembers++;
                System.out.println(onlineMembers);
            }
        }
        return onlineMembers;
    }

//And I've created a CustomActivity class to make the code cleaner when calling it from the bot's .setActivity

public class CustomActivity extends ActivityImpl {
    private BotEventListener eventListener;


    public CustomActivity(BotEventListener eventListener) {
        super(null);
        this.eventListener = eventListener;
    }

    @Override
    public String getName() {
        int onlineMembers = eventListener.getQuantityOnlineMembers();
        return "Users online: " + String.valueOf(onlineMembers);
    }
}

I've noticed that once the bot starts, it never goes back to update its activity display. Maybe creating a map to the amount of users and updating it forcefully when the observer in onUserUpdateOnlineStatus is triggered.


Solution

  • You should use a scheduler to update the activity in a set interval:

    // Build your JDA instance
    JDA jda = JDABuilder...build();
    
    // Every 60 seconds (don't update this too quickly)
    jda.getGatewayPool().scheduleAtFixedRate(() -> {
      int onlineMembers = eventListener.getQuantityOnlineMembers();
      jda.getPresence().setActivity(Activity.listening("Users online: " + onlineMembers));
    }, 0, 60, TimeUnit.SECONDS);