Registering commands

Declare and handle commands from a Python plugin.

This page covers how to declare and handle commands in Python, from a one-line command up to sub-commands and sender checks. For usage-string syntax, parameter types, and enums, see Creating commands.

Declare a command

Commands are declared as a commands class attribute on your plugin - a dict keyed by command name:

src/endstone_my_plugin/my_plugin.py
from endstone.plugin import Plugin

class MyPlugin(Plugin):
    api_version = "0.11"

    commands = {
        "hello": {
            "description": "Greet the command sender.",
            "usages": ["/hello"],
        }
    }

Each entry takes a description and a list of usages - the usage strings the client parses for tab-completion.

api_version is the major.minor of the Endstone API you build against. Set it to match your installed Endstone.

Control who can run it

By default every command requires the operator permission. To let everyone use /hello, attach a permission and set its default:

src/endstone_my_plugin/my_plugin.py
from endstone.plugin import Plugin

class MyPlugin(Plugin):
    api_version = "0.11"

    commands = {
        "hello": {
            "description": "Greet the command sender.",
            "usages": ["/hello"],
            "permissions": ["my_plugin.command.hello"],
        }
    }

    permissions = {
        "my_plugin.command.hello": {
            "description": "Allow users to use the /hello command.",
            "default": True,
        }
    }

The default field sets who holds the permission:

ValueWho can run it
TrueEveryone
FalseNo one, unless explicitly granted
"op"Operators only
"not_op"Non-operators only
"console"Console only

Handle the command

Override on_command to run when the command is executed. Return True if you handled it, or False to show the usage message:

src/endstone_my_plugin/my_plugin.py
from endstone.command import Command, CommandSender
from endstone.plugin import Plugin

class MyPlugin(Plugin):
    # ...

    def on_command(self, sender: CommandSender, command: Command, args: list[str]) -> bool:
        if command.name == "hello":
            sender.send_message("Hello World!")
        return True

Read parameters

args holds the parsed parameters in order. Declaring /hello [msg: message] makes msg optional, so check whether it was provided:

src/endstone_my_plugin/my_plugin.py
    commands = {
        "hello": {
            "description": "Greet the command sender.",
            "usages": ["/hello [msg: message]"],
            "permissions": ["my_plugin.command.hello"],
        }
    }

    def on_command(self, sender: CommandSender, command: Command, args: list[str]) -> bool:
        if command.name == "hello":
            if len(args) == 0:
                sender.send_message("Hello World!")
            else:
                sender.send_message(args[0])
        return True

Branch on a sub-command

A single command can offer a fixed set of actions with an enum parameter. Declare the choices in the usage string and dispatch on the first argument:

src/endstone_my_plugin/my_plugin.py
    commands = {
        "warp": {
            "description": "Manage warps.",
            "usages": ["/warp <add|list|del>"],
        }
    }

    def on_command(self, sender: CommandSender, command: Command, args: list[str]) -> bool:
        if command.name == "warp":
            action = args[0]
            if action == "add":
                sender.send_message("Warp added.")
            elif action == "list":
                sender.send_message("Listing warps...")
            elif action == "del":
                sender.send_message("Warp deleted.")
        return True

Because the parameter is mandatory, the client only accepts one of the listed values, so args[0] is always one of them.

Restrict to players

A command can be run from the console as well as in-game. When your logic needs an actual player, guard with isinstance and bail out gracefully otherwise:

src/endstone_my_plugin/my_plugin.py
from endstone import Player
from endstone.command import Command, CommandSender

    def on_command(self, sender: CommandSender, command: Command, args: list[str]) -> bool:
        if command.name == "ping":
            if not isinstance(sender, Player):
                sender.send_message("Only players can run this command.")
                return True
            sender.send_popup("Pong!")
        return True

See Creating commands for the full set of parameter types and enum syntax.

On this page