Introduction

This page explains how to run your own instance of Pablo! and how to develop your own plugins to use for the bot if you are a Java Developer.

The download links to Pablo! can be found here.

Setup the Bot

Download and Installation

Download the bot from the link above and keep it in a seperate folder. Run the command below to start up the bot and to generate the config.yml

Adjust the RAM usage accordingly to how much you want to allocate for Pablo!.

java -Xmx[RAM in MB]M -Xms[RAM in MB]M -Djava.awt.headless=false -jar PabloBotRewritten.jar

Additional Arguments:

--nogui - Disables showing the GUI, --noansi - Disables ANSI Encoding

Configuration Example

# The bot name to be shown in embed messages
botName: "Pablo! 2022"

# The release channel for this bot, for updates to be checked (release, beta)
releaseChannel: "release"

# Set to false, if you don't want hourly update checks
checkForUpdates: true

# The bot token to login to. You can grab this from Discords Developer Portal
token: "none"

# The users to give access to all commands without required permissions.
adminUserID:
- "214029393809506306"
- "315390446904016908"
- "949067213762080808"

# The activity text to show on the bot when it's online (PLAYING, STREAMING, WATCHING, LISTENING, COMPETING)
activityType: "LISTENING"

# %s = Servers the bot is on
activityText: "p!help or /help | %s Servers"

# Default Prefix to use if not defined
defaultPrefix: "p!"

# Enable all plugins for all servers and disables the plugin command for Discord
enableAllPluginsForAllServers: true

# Custom Invite URL to be used when executing the invite command, you can set it to "none" to disable this
customInviteURL: "https://invite.pablobot.net/"

# Custom Beta Invite URL to be used when executing the invite command, you can set it to "none" to disable this
customBetaInviteURL: "https://betainvite.pablobot.net/"

# The bot image to be shown in embed messages, you can set it to "self" for the bots discord avatar
botImageURL: "self"

# The message to show when a user does the help command, you can set it to "none" to disable this
helpDescription: "none"

# The header message to show on every embed message
embedHeaderMessage: "Pablo! 2022 - The ultimate bot that replaces multiple bots!"

# The header image to show on every embed message, you can set it to "self" for the bots discord avatar
embedHeaderImage: "self"

# The header link to be clicked on every embed header, you can set it to "none" if you don't want to set a link
embedHeaderLink: "none"

# The footer message to show on every embed message
embedFooterMessage: "Created by Logicism#9308 | https://logicism.tv/"

# The footer image to show on every embed message, you can set it to "self" for the bots discord avatar
embedFooterImage: "https://d1fdloi71mui9q.cloudfront.net/V7doboTvm5fuyfxtuuow_j50qJdbokA0z9z8S"

Console Commands

These are all the commands that are available on console.

<> = Required [] = Optional

connectedvc - Get a list of voice channels the bot is connected to

Command Usage:

connectedvc [Page Number]

Example:

connectedvc 2

errors - List, view, delete errors

Command Usage:

errors <list/view/delete> <Error ID>

Example:

errors view 793047406

help - Show the help menu

Command Usage:

help

invites - Retrieve an invite from every server

Command Usage:

invites

plugins - List the plugins installed

Command Usage:

plugins

reload - Reload config.yml and servers.json

Command Usage:

reload

servers - Get a list of servers the bot is on

Command Usage:

servers

stop - Stop the bot

Command Usage:

stop

Creating a Plugin

This section teaches you have to make a Pablo! plugin that is based on Java code. If you are looking into learning how to code in Java, you can look into watching YouTube videos or look into a learning platform called LinkedIn Learning. If you are a Minecraft Plugin Dev, you will notice that the API is designed to be similar to Bukkit's API.

Maven Dependency Import

Pablo! is not hosted on a repo (yet). You must add it in manually through Maven.

<dependency>
        <groupId>me.Logicism.PabloBotRewritten</groupId>
        <artifactId>PabloBotRewritten</artifactId>
	<version>1.5</version>
</dependency>

Dependency Manual Import

If you do not want to use Maven, you can import the bot jar into your project IDE.

Creating the plugin class

public class TestPlugin extends Plugin {

    public static Plugin plugin;

    @Override
    public void onEnable() {
        plugin = this;
    }

    @Override
    public void onDisable() {
        plugin = null;
    }
}

Registering Commands

Some classes implements the usage of JDA objects.

public class TestPlugin extends Plugin {

    public static Plugin plugin;

    @Override
    public void onEnable() {
        plugin = this;

        PabloBotRewritten.getInstance().getCommandManager().registerDiscordCommand(new DiscordCommand("testcommand", "Test Command", 
		List.of(new OptionData(OptionType.STRING, "required", "The required option").setRequired(true), new OptionData(OptionType.STRING, "optional", "The optional option")),
		List.of(new DiscordSubCommand("subcmd", "The first subcommand", null), 
			new DiscordSubCommand("subcmd1", "The second subcommand", null), 
			new DiscordSubCommand("subcmd2", "The third subcommand with an option", List.of(new OptionData(OptionType.STRING, "required", "The required option", true))))
		, plugin), new TestErrorCommand());
		
        PabloBotRewritten.getInstance().getCommandManager().registerConsoleCommand(new ConsoleCommand("testcommand", "Test Command", plugin), new TestCommand());
    }

    @Override
    public void onDisable() {
        plugin = null;
        config = null;
    }
}
public class TestCommand implements DiscordCommandExecutor {
    @Override
    public boolean onCommand(Member member, User user, MessageChannel channel, String s, String[] strings) {
        channel.sendMessage("Test Command").queue();
        return false;
    }

    @Override
    public boolean onCommand(Member member, User user, InteractionHook hook, String subcmd, String s, List<OptionMapping> list) {
        if (subcmd.equals("subcmd")) {
            hook.sendMessage("This is the first subcommand!").queue();
        } else if (subcmd.equals("subcmd1")) {
            hook.sendMessage("This is the second subcommand!").queue();
        } else if (subcmd.equals("subcmd2")) {
            hook.sendMessage("This is the third subcommand with the option:" + list.get(0).getAsString() + " !").queue();
        }
        return false;
    }
}

Adding Configuration

public class TestPlugin extends Plugin {

    public static Plugin plugin;
    public static FileConfiguration config;

    @Override
    public void onEnable() {
        plugin = this;
	config = getConfig();
		
	config.addDefault("test1", "value1");
        config.addDefault("test2.testA", "value2");
        config.addDefault("test2.testB", "value3");
        config.options().copyDefaults(true);

        saveConfig();

        PabloBotRewritten.getInstance().getCommandManager().registerDiscordCommand(new DiscordCommand("testcommand", "Test Command", 
		List.of(new OptionData(OptionType.STRING, "required", "The required option").setRequired(true), new OptionData(OptionType.STRING, "optional", "The optional option")),
		List.of(new DiscordSubCommand("subcmd", "The first subcommand", null), 
			new DiscordSubCommand("subcmd1", "The second subcommand", null), 
			new DiscordSubCommand("subcmd2", "The third subcommand with an option", List.of(new OptionData(OptionType.STRING, "required", "The required option", true))))
		, plugin), new TestErrorCommand());
		
        PabloBotRewritten.getInstance().getCommandManager().registerConsoleCommand(new ConsoleCommand("testcommand", "Test Command", plugin), new TestErrorCommand());
    }

    @Override
    public void onDisable() {
        plugin = null;
        config = null;
    }
}

Registering Message & User Context Items

OptionData class is from JDA.

public class TestPlugin extends Plugin {

    public static Plugin plugin;
    public static FileConfiguration config;

    @Override
    public void onEnable() {
        plugin = this;
	config = getConfig();
		
	config.addDefault("test1", "value1");
        config.addDefault("test2.testA", "value2");
        config.addDefault("test2.testB", "value3");
        config.options().copyDefaults(true);

        saveConfig();

        PabloBotRewritten.getInstance().getCommandManager().registerDiscordCommand(new DiscordCommand("testcommand", "Test Command", 
		List.of(new OptionData(OptionType.STRING, "required", "The required option").setRequired(true), new OptionData(OptionType.STRING, "optional", "The optional option")),
		List.of(new DiscordSubCommand("subcmd", "The first subcommand", null), 
			new DiscordSubCommand("subcmd1", "The second subcommand", null), 
			new DiscordSubCommand("subcmd2", "The third subcommand with an option", List.of(new OptionData(OptionType.STRING, "required", "The required option", true))))
		, plugin), new TestErrorCommand());
		
        PabloBotRewritten.getInstance().getCommandManager().registerConsoleCommand(new ConsoleCommand("testcommand", "Test Command", plugin), new TestErrorCommand());
		
	PabloBotRewritten.getInstance().getCommandManager().registerMessageContextItem(new MessageContextItem("Test Message", null, plugin), new TestMessageContextItem());

        PabloBotRewritten.getInstance().getCommandManager().registerUserContextItem(new UserContextItem("Test User", null, plugin), new TestUserContextItem());
    }

    @Override
    public void onDisable() {
        plugin = null;
        config = null;
    }
}
public class TestMessageContextItem implements MessageContextAction {

    @Override
    public void execute(Message message, Member member, User user, InteractionHook hook, String s) {
        hook.sendMessage("The messaged you executed this action to is `" + message.getContentRaw() + "` and you are " + user.getAsTag()).queue();
    }

}
public class TestUserContextItem implements UserContextAction {

    @Override
    public void execute(Member member, User user, Member memberAuthor, User userAuthor, InteractionHook hook, String s) {
        hook.sendMessage("The user you executed this action to is " + user.getAsTag() + " and you are " + userAuthor.getAsTag()).queue();
    }

}

Registering Custom Help Menu

public class TestPlugin extends Plugin {

    public static Plugin plugin;
    public static FileConfiguration config;

    @Override
    public void onEnable() {
        plugin = this;
	config = getConfig();
		
	config.addDefault("test1", "value1");
        config.addDefault("test2.testA", "value2");
        config.addDefault("test2.testB", "value3");
        config.options().copyDefaults(true);

        saveConfig();

        PabloBotRewritten.getInstance().getCommandManager().registerDiscordCommand(new DiscordCommand("testcommand", "Test Command", 
		List.of(new OptionData(OptionType.STRING, "required", "The required option").setRequired(true), new OptionData(OptionType.STRING, "optional", "The optional option")),
		List.of(new DiscordSubCommand("subcmd", "The first subcommand", null), 
			new DiscordSubCommand("subcmd1", "The second subcommand", null), 
			new DiscordSubCommand("subcmd2", "The third subcommand with an option", List.of(new OptionData(OptionType.STRING, "required", "The required option", true))))
		, plugin), new TestErrorCommand());
		
        PabloBotRewritten.getInstance().getCommandManager().registerConsoleCommand(new ConsoleCommand("testcommand", "Test Command", plugin), new TestErrorCommand());
		
	PabloBotRewritten.getInstance().getCommandManager().registerMessageContextItem(new MessageContextItem("Test Message", null, plugin), new TestMessageContextItem());

        PabloBotRewritten.getInstance().getCommandManager().registerUserContextItem(new UserContextItem("Test User", null, plugin), new TestUserContextItem());
		
	setHelpMenu(new TestPluginHelpMenu());
    }

    @Override
    public void onDisable() {
        plugin = null;
        config = null;
    }
}
public class TestPluginHelpMenu extends PluginHelpMenu {

    @Override
    public void executeHelpMenu(Member member, MessageChannel channel) {
        EmbedBuilder eb = new EmbedBuilder();
        eb.setAuthor("TestPlugin Help Menu");
        eb.addField("Commands to Test Pablo!'s Functionality", GuildUtils.getGuildPrefix(((TextChannel) channel).getGuild().getId()) + "testcommand - Test Command", true);
        eb.setFooter("Custom Help Menu Test");
        channel.sendMessageEmbeds(eb.build()).queue();
    }

    @Override
    public void executeHelpMenu(Member member, InteractionHook hook) {
        EmbedBuilder eb = new EmbedBuilder();
        eb.setAuthor("TestPlugin Help Menu");
        eb.addField("Commands to Test Pablo!'s Functionality", "/testcommand - Test Command", true);
        eb.setFooter("Custom Help Menu Test");
        hook.sendMessageEmbeds(eb.build()).queue();
    }

    @Override
    public void executeHelpMenu(Member member, SelectMenuInteractionEvent e) {
        EmbedBuilder eb = new EmbedBuilder();
        eb.setAuthor("TestPlugin Help Menu");
        if (e.getMessage().getType().equals(MessageType.SLASH_COMMAND)) {
            eb.addField("Commands to Test Pablo!'s Functionality", "/testerror - Test the ErrorManager\n" + "/testconfig - Test the Configuration", true);
        } else {
            eb.addField("Commands to Test Pablo!'s Functionality", GuildUtils.getGuildPrefix(e.getGuild().getId()) + "testcommand - Test Command", true);
        }
        eb.setFooter("Custom Help Menu Test");
        e.editMessageEmbeds(eb.build()).queue();
    }
}

Working with Events

Events can be handled the same way you code a JDA Bot.

public class TestPlugin extends Plugin {

    public static Plugin plugin;
    public static FileConfiguration config;

    @Override
    public void onEnable() {
        plugin = this;
	config = getConfig();
		
	config.addDefault("test1", "value1");
        config.addDefault("test2.testA", "value2");
        config.addDefault("test2.testB", "value3");
        config.options().copyDefaults(true);

        saveConfig();

        PabloBotRewritten.getInstance().getCommandManager().registerDiscordCommand(new DiscordCommand("testcommand", "Test Command", 
		List.of(new OptionData(OptionType.STRING, "required", "The required option").setRequired(true), new OptionData(OptionType.STRING, "optional", "The optional option")),
		List.of(new DiscordSubCommand("subcmd", "The first subcommand", null), 
			new DiscordSubCommand("subcmd1", "The second subcommand", null), 
			new DiscordSubCommand("subcmd2", "The third subcommand with an option", List.of(new OptionData(OptionType.STRING, "required", "The required option", true))))
		, plugin), new TestErrorCommand());
		
        PabloBotRewritten.getInstance().getCommandManager().registerConsoleCommand(new ConsoleCommand("testcommand", "Test Command", plugin), new TestErrorCommand());
		
	PabloBotRewritten.getInstance().getCommandManager().registerMessageContextItem(new MessageContextItem("Test Message", null, plugin), new TestMessageContextItem());

        PabloBotRewritten.getInstance().getCommandManager().registerUserContextItem(new UserContextItem("Test User", null, plugin), new TestUserContextItem());
		
	setHelpMenu(new TestPluginHelpMenu());
	
	PabloBotRewritten.getInstance().getJDA().addEventListener(new InteractionsEvents());
    }

    @Override
    public void onDisable() {
        plugin = null;
        config = null;
    }
}
public class InteractionsEvents extends ListenerAdapter {

    @Override
    public void onButtonInteraction(@NotNull ButtonInteractionEvent event) {
        if (event.getComponentId().equals("testplugin_button1")) {
            event.reply("You clicked on a primary button!").queue();
        } else if (event.getComponentId().equals("testplugin_button2")) {
            event.reply("You clicked on a secondary button!").queue();
        } else if (event.getComponentId().equals("testplugin_button3")) {
            event.reply("You clicked on a danger button!").queue();
        } else if (event.getComponentId().equals("testplugin_button4")) {
            event.reply("You clicked on a success button!").queue();
        }
    }

    @Override
    public void onSelectMenuInteraction(@NotNull SelectMenuInteractionEvent event) {
        if (event.getComponentId().equals("testplugin_selectionmenu")) {
            SelectMenu.Builder sm = SelectMenu.fromData(event.getSelectMenu().toData()).setDefaultValues(event.getValues());
            SelectOption option = event.getSelectedOptions().get(0);

            if (option.getValue().equals("testselection1")) {
                event.editMessage("You clicked on the first selection!").setActionRow(sm.build()).queue();
            } else if (option.getValue().equals("testselection2")) {
                event.editMessage("You clicked on the second selection!").setActionRow(sm.build()).queue();
            } else if (option.getValue().equals("testselection3")) {
                event.editMessage("You clicked on the third selection!").setActionRow(sm.build()).queue();
            }
        } else if (event.getComponentId().equals("testplugin_multiselectionmenu")) {
            SelectMenu.Builder sm = SelectMenu.fromData(event.getSelectMenu().toData()).setDefaultValues(event.getValues());
            List<String> selectedOptions = new ArrayList<>();
            for (SelectOption option : event.getSelectedOptions()) {
                selectedOptions.add(option.getLabel());
            }

            event.editMessage("You selected on: " + StringUtils.join(selectedOptions, ", ")).setActionRow(sm.build()).queue();
        }
    }
}

Scheduled and Repeating Tasks

The time is in milliseconds

public class TestPlugin extends Plugin {

    public static Plugin plugin;
    public static FileConfiguration config;
	
private static int repeatingTaskID;
private static int scheduledTaskID;

    @Override
    public void onEnable() {
        plugin = this;
	config = getConfig();
		
	config.addDefault("test1", "value1");
        config.addDefault("test2.testA", "value2");
        config.addDefault("test2.testB", "value3");
        config.options().copyDefaults(true);

        saveConfig();

        PabloBotRewritten.getInstance().getCommandManager().registerDiscordCommand(new DiscordCommand("testcommand", "Test Command", 
		List.of(new OptionData(OptionType.STRING, "required", "The required option").setRequired(true), new OptionData(OptionType.STRING, "optional", "The optional option")),
		List.of(new DiscordSubCommand("subcmd", "The first subcommand", null), 
			new DiscordSubCommand("subcmd1", "The second subcommand", null), 
			new DiscordSubCommand("subcmd2", "The third subcommand with an option", List.of(new OptionData(OptionType.STRING, "required", "The required option", true))))
		, plugin), new TestErrorCommand());
		
        PabloBotRewritten.getInstance().getCommandManager().registerConsoleCommand(new ConsoleCommand("testcommand", "Test Command", plugin), new TestErrorCommand());
		
	PabloBotRewritten.getInstance().getCommandManager().registerMessageContextItem(new MessageContextItem("Test Message", null, plugin), new TestMessageContextItem());

        PabloBotRewritten.getInstance().getCommandManager().registerUserContextItem(new UserContextItem("Test User", null, plugin), new TestUserContextItem());
		
	setHelpMenu(new TestPluginHelpMenu());
	
	PabloBotRewritten.getInstance().getJDA().addEventListener(new InteractionsEvents());
	
	repeatingTaskID = PabloBotRewritten.getInstance().getScheduler().runRepeatingTask(plugin, new Runnable() {
		getLogger().info("This is a test message that is repeating for 5 minutes");
	}, 300000, 300000);
	
	scheduledTaskID = PabloBotRewritten.getInstance().getScheduler().runScheduledTask(plugin, new Runnable() {
		getLogger().info("This is a test message that is scheduled after 5 minutes");
	}, 300000);
    }

    @Override
    public void onDisable() {
        plugin = null;
        config = null;
		
		PabloBotRewritten.getInstance().getScheduler().cancelTask(repeatingTaskID);
    }
}

Creating the plugin.yml

This file goes in the resources directory or the root of the source folder.

name: TestPlugin
description: A plugin to test all functionality of PabloBot Rewritten
version: 1.4
apiVersion: 1.5
main: me.Logicism.PabloBotRewrittenTestPlugin.TestPlugin
author: Logicism
website: TestWebsite