LiteCommands Framework

repository·master·Indexed 42 days ago

https://github.com/rollczi/litecommands

An annotation-based command framework for Java and Kotlin, supporting platforms such as Minecraft server software (Bukkit, Velocity, Fabric, Paper, BungeeCord, Minestom, Sponge) and chat bots (JDA, Telegram). It features a fluent CommandBuilder API, asynchronous support via @Async, and deep integration with Kyori Adventure for component resolution.

Tokens
11.6K
Snippets
35
Records
46
Agent score
49%

What's inside LiteCommands

  1. Overview of LiteCommands features

    master

    LiteCommands is an annotation-based command framework supporting multiple platforms (Velocity, Bukkit, Paper, BungeeCord, Minestom, Sponge, Fabric, JDA, TelegramBots).

    Key features include:

    • Argument Types: Supports basic types (int, double, Duration, LocalDateTime, Location), collection types (List, Set, TreeSet, Queue, arrays), and specialized annotations like @Quoted for quoted input.
    • Argument Modifiers: @Arg, @OptionalArg, @Flag, @Join (joins remaining arguments into a string), and @Literal.
    • Context Providers: Use annotations like @Sender Player or @Context World to inject environment data.
    • Asynchronous Support: Use the @Async annotation for asynchronous command execution and parsing.
    • Extensibility: Supports custom validators, programmatic API for dynamic commands, and extensions for Jakarta EE, ChatGPT, and Adventure Kyori.
  2. Use the LiteCommands IntelliJ Plugin

    master

    For an improved development experience in IntelliJ IDEA, you can install the official LiteCommands plugin. It provides:

    • Annotation inspections
    • Syntax highlighting
    • Code completion
    • Tools for creating new command classes
  3. Install LiteCommands

    master

    To use LiteCommands, you must first add the Panda repository to your build configuration and then add the appropriate platform-specific artifact as a dependency.

    Important: You must add the -parameters flag to your Java compiler to enable all LiteCommands features (such as parameter name reflection).

    ### Gradle (Kotlin DSL)
    
    ```kts
    // Add Panda Repository
    maven("https://repo.panda-lang.org/releases")
    
    // Add LiteCommands dependency
    // Replace {artifact} with your platform artifact (e.g., litecommands-bukkit)
    implementation("dev.rollczi:{artifact}:3.11.0")

    Maven

    <!-- Add Panda Repository -->
    <repository>
        <id>panda-repository</id>
        <url>https://repo.panda-lang.org/releases</url>
    </repository>
    
    <!-- Add LiteCommands dependency -->
    <!-- Replace {artifact} with your platform artifact (e.g., litecommands-bukkit) -->
    <dependency>
        <groupId>dev.rollczi</groupId>
        <artifactId>{artifact}</artifactId>
        <version>3.11.0</version>
    </dependency>
  4. Understand the Command Execution Lifecycle and Events

    master

    The CommandExecuteService follows a specific lifecycle that allows developers to intercept and modify execution via events. The following events are published during the process:

    1. CommandExecutorNotFoundEvent: Published if no suitable executor is found for the provided CommandRoute.
    2. CommandExecutorFoundEvent: Published after an executor is found and its arguments are successfully matched via the RequirementMatchService.
    3. CommandPreExecutionEvent: Published after matching is successful but before the command is actually executed. This event can be used to cancel execution.
    4. CommandPostExecutionEvent: Published after the command has finished executing. This event allows for post-processing the CommandExecuteResult.

    If any of these events are cancelled (e.g., via matchEvent.isCancelled() or executionEvent.isCancelled()), the service returns a failed CommandExecuteResult with the corresponding cancel reason.

  5. How AdventurePlatformAudienceProvider resolves Audiences in Bukkit

    master

    The AdventurePlatformAudienceProvider is used to map command senders to Kyori Adventure Audience objects within a Bukkit environment. It determines the correct audience based on the Invocation and the PlatformSender's Identifier.

    Resolution logic follows this priority:

    1. Direct Audience: If the command sender is already an instance of net.kyori.adventure.audience.Audience, it is returned directly.
    2. Console: If the PlatformSender identifier is Identifier.CONSOLE, it returns the audience provided by audienceProvider.console().
    3. Player: If the identifier contains a UUID, it returns the audience provided by audienceProvider.player(UUID).
    4. Raw Text: If the PlatformSender implements PlatformReceiver, it wraps the sender in a RawTextAudience.

    If none of these conditions are met, it throws an IllegalArgumentException indicating an unsupported command sender type.

  6. Understand the Command Execution Event lifecycle

    master

    When using LiteCommands, the execution of a command follows a specific sequence of events. If you are implementing event listeners to intercept or react to command execution, you should be aware of the following lifecycle flow:

    1. CommandExecutorFoundEvent: Fired when a suitable command executor is identified.
    2. CommandPreExecutionEvent: Fired immediately before the command's logic is executed.
    3. CommandPostExecutionEvent: Fired after the command's logic has completed.

    Note: The CommandExecutorEvent interface is marked as @ApiStatus.Experimental and is part of the event system used to monitor these stages.

  7. Understand the CommandNode interface

    master

    The CommandNode<SENDER> interface represents any node within the command tree structure. It serves as a base component that can be part of a command hierarchy. Every CommandNode implements MetaHolder, allowing it to hold metadata.

    Key characteristics:

    • Generics: It is parameterized by SENDER, representing the type of the object that triggers the command (e.g., a player in a game engine or a user in a shell).
    • Hierarchy: Each node can access its parent via getParent(), which returns a CommandRoute<SENDER>.
    • Metadata: Through the parentMeta() default method, a node can access the metadata of its parent node in the tree.
    /**
     * CommandNode is an any node of the command tree.
     * @see CommandRoute
     * @see dev.rollczi.litecommands.command.executor.CommandExecutor
     */
    public interface CommandNode<SENDER> extends MetaHolder {
        CommandRoute<SENDER> getParent();
    
        @Override
        @Nullable
        default MetaHolder parentMeta() {
            return getParent();
        }
    }
  8. Create a command hierarchy with appendChild and editChild

    master

    Commands in LiteCommands can be nested to create subcommands. Use the following methods to manage the hierarchy:

    • appendChild(String name, UnaryOperator<CommandBuilder<SENDER>> operator): Creates a new child command with the specified name and configures it using the provided operator.
    • appendChild(CommandBuilder<SENDER> context): Adds an existing CommandBuilder instance as a child.
    • editChild(String name, UnaryOperator<CommandBuilder<SENDER>> operator): Finds an existing child by name and applies a configuration operator to it.
    • getChild(String name): Returns an Optional<CommandBuilder<SENDER>> containing the child if it exists.
    • children(): Returns a collection of all child commands.
    CommandBuilder<MySender> builder = CommandBuilder.create()
        .name("main")
        .appendChild("sub", sub -> sub.name("subcommand"))
        .editChild("sub", sub -> sub.aliases("alt-sub"));
  9. Understand the CommandRoute abstraction

    master

    A CommandRoute<SENDER> represents a node within the command tree. It can function as either a top-level command (root) or a subcommand. Each route is identified by a name and can have multiple aliases.

    Key characteristics:

    • Hierarchy: Routes can have a parent and multiple children (subcommands), forming a tree structure.
    • Execution: A route can hold multiple CommandExecutor<SENDER> instances, which are responsible for executing the logic associated with that specific command or subcommand.
    • Metadata: Every route provides access to its Meta object for additional descriptive information.
    • Scope: It implements Scopeable, allowing it to participate in scoped command contexts.
  10. Register commands in Bukkit

    master

    After defining your command class, you must register it using the platform-specific factory. For Bukkit/Spigot/Paper, use LiteBukkitFactory.

    this.liteCommands = LiteBukkitFactory.builder("example-plugin")
        .commands(new HelloCommand())
        .build();
  11. Create a command with annotations

    master

    LiteCommands uses an annotation-based model to define commands. You define a class annotated with @Command and a method annotated with @Execute. Arguments are handled via annotations like @Arg, @OptionalArg, @Flag, and @Sender (for context providers).

    @Command(name = "hello")
    @Permission("dev.rollczi.helloworld")
    public class HelloCommand {
    
        @Execute
        void command(@Sender CommandSender sender, @Arg String name, @Arg int amount) {
            for (int i = 0; i < amount; i++) {
                sender.sendMessage("Hello " + name);
            }
        }
    }
  12. Manage CommandManager lifecycle

    master

    The CommandManager provides methods to control the lifecycle of the command system:

    • registerAll(): Starts the underlying Platform. This should be called after all command routes have been registered.
    • unregisterAll(): Performs a full cleanup. It clears all children from the root route, unregisters all routes from the platform, and stops the platform.
    public void registerAll() {
        this.platform.start();
    }
    
    public void unregisterAll() {
        this.root.clearChildren();
        this.platform.unregisterAll();
        this.platform.stop();
    }