Skip to content

F | Creating Custom Commands

Sartaj Singh edited this page May 31, 2025 · 2 revisions

F | Creating Custom Commands


Table of Contents


1. Overview

FXItems supports the creation and dynamic registration of custom commands using the Bukkit/Spigot API, but with a modern registry-centric pattern. You can register commands at runtime, modularize your command logic, and integrate commands with custom items, foods, or advanced abilities.


2. Command System Architecture

  • Commands are registered through the FXItems Registry API.
  • Each command is implemented as a Java class that implements CommandExecutor.
  • The registration system allows for dynamic, on-the-fly registration and unregistration—no plugin reload required.
  • Commands can interact with FXItems systems, including item/food registries, utility APIs, cooldowns, and more.

3. Command Registration

3.1 Manual Registration

To register a command, call the registry in your plugin's onEnable() or initialization logic:

Registry registry = new RegistryAPI();
registry.registerCommand(
    this,                  // Plugin instance
    "giveitem",            // Command name (no slash)
    GiveItemCommand.class  // Your class (implements CommandExecutor)
);

Parameters:

  • plugin: Your main plugin instance (typically this).
  • name: Command name, no slash, all lowercase recommended.
  • cmdClass: The class of your command (must implement CommandExecutor and have a public no-argument constructor).

3.2 Auto-Registration (For Large Projects)

If you have many commands, you can use a pattern similar to the auto-registration of items/behaviors:

  • Place all command classes in a specific package.
  • Write a reflection-based registrar (or use one if provided by FXItems) to auto-register all classes implementing CommandExecutor.

4. Command Classes: Implementing CommandExecutor

4.1 Basic Command Structure

Your command class must implement CommandExecutor and have a public no-argument constructor:

public class GiveItemCommand implements CommandExecutor {
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        if (!(sender instanceof Player player)) {
            sender.sendMessage("§cThis command is player-only.");
            return true;
        }
        if (args.length < 1) {
            player.sendMessage("§eUsage: /giveitem <itemid>");
            return true;
        }
        String id = args[0].toLowerCase();
        FXItemDefinition def = ItemRegistry.getItemDefinition(id);
        if (def == null) {
            player.sendMessage("§cUnknown item: " + id);
            return true;
        }
        player.getInventory().addItem(ItemRegistry.getCustomItem(id));
        player.sendMessage("§aYou received: " + def.getDisplayName());
        return true;
    }
}

4.2 Advanced Command Patterns

  • Tab Completion: Implement TabCompleter for suggestions.
  • Subcommands: Parse args[] for multi-level commands (e.g., /fxitems reload).
  • Permission Checks: Use sender.hasPermission("yourplugin.cmd").
  • Integration: Use FXItems APIs within commands (give items/foods, trigger effects, modify mana, etc.).
  • Feedback: Use color codes and clear error messages for users.

5. Command Options and Features

  • Dynamic Registration: Commands are available as soon as they're registered (no server reload needed).
  • Multiple Commands: Register as many as you want; each must have a unique name.
  • Integration: Commands can interact with FXItems content (give items, spawn foods, debug info, etc.).
  • Advanced Usage: Register event listeners or schedule tasks from within command logic.

6. Example Custom Commands

Example 1: /getfood <foodid>

public class GetFoodCommand implements CommandExecutor {
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        if (!(sender instanceof Player player)) {
            sender.sendMessage("§cThis command is player-only.");
            return true;
        }
        if (args.length < 1) {
            player.sendMessage("§eUsage: /getfood <foodid>");
            return true;
        }
        String id = args[0].toLowerCase();
        FXFoodDefinition def = FoodRegistry.getFoodDefinition(id);
        if (def == null) {
            player.sendMessage("§cUnknown food: " + id);
            return true;
        }
        player.getInventory().addItem(FoodRegistry.getCustomFood(id));
        player.sendMessage("§aYou received: " + def.getDisplayName());
        return true;
    }
}

Example 2: /iteminfo <itemid>

public class ItemInfoCommand implements CommandExecutor {
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
        if (args.length < 1) {
            sender.sendMessage("§eUsage: /iteminfo <itemid>");
            return true;
        }
        String id = args[0].toLowerCase();
        FXItemDefinition def = ItemRegistry.getItemDefinition(id);
        if (def == null) {
            sender.sendMessage("§cUnknown item: " + id);
            return true;
        }
        sender.sendMessage("§bItem: " + def.getDisplayName());
        sender.sendMessage("§7Type: " + def.getMaterial().name());
        sender.sendMessage("§7Rarity: " + (def.getRarity() != null ? def.getRarity().name() : "None"));
        // Add more fields as needed
        return true;
    }
}

7. Troubleshooting & FAQ

  • “Command not found”:

    • Confirm you registered it in onEnable() and used the correct name.
    • Class must implement CommandExecutor and have a public no-arg constructor.
  • “Command does nothing”:

    • Check for exceptions in the server log.
    • Make sure your onCommand returns true and sends feedback to the user.
  • Tab completion not working:

    • Implement TabCompleter and register with Bukkit/Spigot if needed.
  • Can I reload commands at runtime?

    • Yes! Simply re-register with a new class instance.

8. See Also


Clone this wiki locally