Skip to content

Designing Commands

Miu edited this page Dec 2, 2023 · 13 revisions

Caution

Before we dive in, when using Nexus, it's advised to avoid employing the event.interaction.respondLater() methods provided by Javacord. This is due to the special handling of middleware in Nexus, which necessitates coordination between the command and middleware. Instead, it's recommended to use event.respondLater() or event.respondLaterAsEphemeral().

An even more streamlined option is auto-deferring, which takes care of these scenarios for you. To learn more, refer to Auto-deferring Commands.

Designing commands within Nexus is straightforward and elegant. However, before we delve into command design, it's essential to grasp some foundational guidelines that Nexus enforces:

  1. Commands must have distinct names. If you need to reuse a name, you can modify one of the commands with the @IdentifiableAs annotation for indexing purposes.
  2. You must implement the NexusHandler interface for the command to be recognized by the engine.
  3. Each command must include a name and description field, as Discord requires.

With these principles in mind, you can begin crafting a command by creating a class that implements the NexusHandler interface:

object PingCommand: NexusHandler {
    override fun onEvent(event: NexusCommandEvent) {
        // Command logic will be added here
    }
}

However, this alone won't suffice. To make it a recognized command, you need to provide the name and description fields:

object PingCommand: NexusHandler {
    val name: String = "ping"
    val description: String = "Ping, Pong!"

    override fun onEvent(event: NexusCommandEvent) {
        // Command logic will be added here
    }
}

This simple structure creates a basic command. Let's delve deeper and add some functionality:

object PingCommand: NexusHandler {
    val name: String = "ping"
    val description: String = "Ping, Pong!"

    override fun onEvent(event: NexusCommandEvent) {
        val server = event.server.orElseThrow()
        
        // Nexus provides two response options: auto-deferring and manual response.
        // The example here demonstrates auto-deferred responses.
        event.autoDefer(ephemeral = false) {
            return@autoDefer NexusMessage.from("Hello ${server.name}")
        }
        
        // Alternatively, you can manually respond like this:
        // event.respondNowWith("Hello ${server.name}!")
    }
}

At this point, the command responds with a simple message like "Hello {server}!" However, there's a challenge: we can't ensure that it's executed within a server context. Not to worry, Nexus has a solution in the form of middlewares and afterwares, concepts commonly found in many web frameworks. Read more about this solution in Command Interceptors (middleware, afterware).

For more information about what properties to override, refer to:

Reactivity for Kotlin

In addition to the above-shown methods, Kotlin developers can enjoy a greater developer-experience in developing reactive, or highly-interactive bots using our newest rendering mechanism: Nexus.R. We recommend using it for developers who are more familiar with web development.

Auto-deferring Commands

Nexus introduces support for auto-deferring responses in both middlewares and commands. However, it's important to understand the context of slash commands in Nexus, specifically the three-second response requirement before deferring. There are two primary aspects within Nexus that can potentially impact this three-second requirement:

  1. Middlewares
  2. The command itself

To address the uncertainty about which aspect exactly triggers auto-deferring, Nexus introduces auto-deferring. However, enabling this feature requires you to enable auto-deferring in both middlewares and the command itself.

To activate auto-deferring in middlewares, please refer to the Deferred Middleware Responses section.

For enabling auto-deferring in commands, utilize the event.autoDefer(ephemeral, function) method instead of other related methods. It's advisable to use this method, particularly when you have long-running middlewares, as it comprehensively handles cases where a middleware requests deferred responses.

Here's how to implement auto-deferring in commands:

override fun onEvent(event: NexusCommandEvent) {
    event.autoDefer(ephemeral = true) { 
        // ... imagine a long-running task
        return@autoDefer NexusMessage.from("Hello")
    }
}

If you want to receive the response from Discord, you can do so by handling the response of the autoDefer method:

override fun onEvent(event: NexusCommandEvent) {
    event.autoDefer(ephemeral = true) { 
        // ... imagine a long-running task
        return@autoDefer NexusMessage.with { 
            setContent("Hello!")
        }
    }.thenAccept { response -> 
        // The updater is only available if the message was processed through deferred response.
        val updater = response.updater
        // Using `getOrRequestMessage` calls `InteractionOriginalResponseUpdater.update()` if the interaction was 
        // answered without deferring. This is necessary because Javacord or Discord doesn't offer immediate access 
        // to the actual message from the response.
        val message = response.getOrRequestMessage()
    }
}

To configure the duration before auto-deferring triggers, you can modify the following setting:

// Default value
Nexus.configuration.global.autoDeferAfterMilliseconds = 2350

This setting controls the time delay, ensuring that auto-deferring only occurs after the specified duration.

To get started with Nexus, we recommend reading the following in chronological:

  1. Installation & Preparing Nexus
  2. Designing Commands
  3. Command Interceptors
  4. Additional Features (Subcommand Router, Option Validation)
  5. Context Menus
  6. Command Synchronization

You may want to read a specific part of handling command and middleware responses:

You can also read about additional features of Nexus:

You can read about synchronizing commands to Discord:

For more additional performance:

Additional configurations:

Clone this wiki locally