Skip to main content

Introduction

LiquidBounce’s command system allows scripts to add custom commands that can be executed from the in-game chat. Commands support parameters, subcommands, auto-completion, and validation.

Basic Command

Here’s a simple command:
SimpleCommand.js
registerScript({
    name: "SimpleCommand",
    version: "1.0.0",
    authors: ["YourName"]
});

registerCommand({
    name: "hello",
    aliases: ["hi", "greet"],
    onExecute: () => {
        Client.displayChatMessage("Hello from custom command!");
    }
});
Usage in-game: .hello or .hi or .greet

Command Structure

registerCommand({
    name: "commandname",        // Required: Command name
    aliases: ["alias1"],        // Optional: Alternative names
    parameters: [],             // Optional: Command parameters
    subcommands: [],           // Optional: Subcommands
    hub: false,                // Optional: Is this a hub command?
    onExecute: (...args) => {  // Required: Execution handler
        // Command logic
    }
});

Command Parameters

Add parameters to your commands:
ParameterCommand.js
registerScript({
    name: "ParameterCommand",
    version: "1.0.0",
    authors: ["YourName"]
});

registerCommand({
    name: "setvalue",
    parameters: [
        {
            name: "amount",
            required: true
        },
        {
            name: "message",
            required: false
        }
    ],
    onExecute: (amount, message) => {
        Client.displayChatMessage(
            "Amount: " + amount + 
            ", Message: " + (message || "none")
        );
    }
});
Usage: .setvalue 100 or .setvalue 100 "Hello World"

Parameter Properties

{
    name: "param",           // Parameter name
    required: true,          // Is this parameter required?
    vararg: false,          // Accept multiple values?
    validate: (value) => {  // Custom validation
        return {
            accept: true,
            value: value,
            error: ""
        };
    },
    getCompletions: (begin, args) => {  // Auto-completion
        return ["suggestion1", "suggestion2"];
    }
}

Vararg Parameters

Accept multiple values for a parameter:
registerCommand({
    name: "broadcast",
    parameters: [
        {
            name: "message",
            required: true,
            vararg: true  // Accepts multiple words
        }
    ],
    onExecute: (...words) => {
        const message = words.join(" ");
        Client.displayChatMessage("Broadcasting: " + message);
    }
});
Usage: .broadcast This is a long message

Parameter Validation

Validate parameters before execution:
ValidatedCommand.js
registerScript({
    name: "ValidatedCommand",
    version: "1.0.0",
    authors: ["YourName"]
});

registerCommand({
    name: "damage",
    parameters: [
        {
            name: "amount",
            required: true,
            validate: (value) => {
                const num = parseInt(value);
                
                if (isNaN(num)) {
                    return {
                        accept: false,
                        error: "Must be a number"
                    };
                }
                
                if (num < 0 || num > 100) {
                    return {
                        accept: false,
                        error: "Must be between 0 and 100"
                    };
                }
                
                return {
                    accept: true,
                    value: num  // Converted to integer
                };
            }
        }
    ],
    onExecute: (amount) => {
        Client.displayChatMessage("Damage: " + amount);
    }
});

Auto-Completion

Provide suggestions for parameters:
AutoCompleteCommand.js
registerScript({
    name: "AutoCompleteCommand",
    version: "1.0.0",
    authors: ["YourName"]
});

registerCommand({
    name: "target",
    parameters: [
        {
            name: "player",
            required: true,
            getCompletions: (begin, args) => {
                // Get online players
                const players = [];
                const playerList = mc.player.connection.getOnlinePlayers();
                
                playerList.forEach((info) => {
                    const name = info.getProfile().getName();
                    if (name.toLowerCase().startsWith(begin.toLowerCase())) {
                        players.push(name);
                    }
                });
                
                return players;
            }
        }
    ],
    onExecute: (playerName) => {
        Client.displayChatMessage("Targeting: " + playerName);
    }
});

Subcommands

Create commands with subcommands:
SubcommandExample.js
registerScript({
    name: "SubcommandExample",
    version: "1.0.0",
    authors: ["YourName"]
});

registerCommand({
    name: "config",
    hub: true,  // This is a hub command (has subcommands)
    subcommands: [
        {
            name: "save",
            onExecute: () => {
                Client.displayChatMessage("Config saved!");
            }
        },
        {
            name: "load",
            onExecute: () => {
                Client.displayChatMessage("Config loaded!");
            }
        },
        {
            name: "reset",
            parameters: [
                {
                    name: "confirm",
                    required: true
                }
            ],
            onExecute: (confirm) => {
                if (confirm === "yes") {
                    Client.displayChatMessage("Config reset!");
                } else {
                    Client.displayChatMessage("Reset cancelled.");
                }
            }
        }
    ]
});
Usage:
  • .config save
  • .config load
  • .config reset yes

Complete Command Example

Here’s a comprehensive command example:
ModuleControl.js
registerScript({
    name: "ModuleControl",
    version: "1.0.0",
    authors: ["YourName"]
});

registerCommand({
    name: "module",
    aliases: ["mod", "m"],
    hub: true,
    subcommands: [
        {
            name: "toggle",
            aliases: ["t"],
            parameters: [
                {
                    name: "moduleName",
                    required: true,
                    getCompletions: (begin, args) => {
                        const modules = Client.moduleManager.modules;
                        const suggestions = [];
                        
                        modules.forEach((module) => {
                            const name = module.name;
                            if (name.toLowerCase().startsWith(begin.toLowerCase())) {
                                suggestions.push(name);
                            }
                        });
                        
                        return suggestions;
                    }
                }
            ],
            onExecute: (moduleName) => {
                const module = Client.moduleManager.getModule(moduleName);
                
                if (module === null) {
                    Client.displayChatMessage("Module not found: " + moduleName);
                    return;
                }
                
                module.enabled = !module.enabled;
                Client.displayChatMessage(
                    module.name + " is now " + 
                    (module.enabled ? "enabled" : "disabled")
                );
            }
        },
        {
            name: "list",
            aliases: ["l"],
            parameters: [
                {
                    name: "category",
                    required: false,
                    getCompletions: (begin, args) => {
                        return [
                            "Combat", "Movement", "Player",
                            "World", "Render", "Client",
                            "Misc", "Fun"
                        ];
                    }
                }
            ],
            onExecute: (category) => {
                const modules = Client.moduleManager.modules;
                const list = [];
                
                modules.forEach((module) => {
                    if (!category || module.category.toString() === category) {
                        list.push(module.name);
                    }
                });
                
                Client.displayChatMessage(
                    "Modules" + (category ? " (" + category + ")" : "") + 
                    ": " + list.join(", ")
                );
            }
        },
        {
            name: "info",
            aliases: ["i"],
            parameters: [
                {
                    name: "moduleName",
                    required: true,
                    getCompletions: (begin, args) => {
                        const modules = Client.moduleManager.modules;
                        const suggestions = [];
                        
                        modules.forEach((module) => {
                            const name = module.name;
                            if (name.toLowerCase().startsWith(begin.toLowerCase())) {
                                suggestions.push(name);
                            }
                        });
                        
                        return suggestions;
                    }
                }
            ],
            onExecute: (moduleName) => {
                const module = Client.moduleManager.getModule(moduleName);
                
                if (module === null) {
                    Client.displayChatMessage("Module not found: " + moduleName);
                    return;
                }
                
                Client.displayChatMessage("--- " + module.name + " ---");
                Client.displayChatMessage("Category: " + module.category);
                Client.displayChatMessage("Enabled: " + module.enabled);
                Client.displayChatMessage("Description: " + module.description.get());
                
                const settings = Object.keys(module.settings);
                if (settings.length > 0) {
                    Client.displayChatMessage("Settings: " + settings.join(", "));
                }
            }
        }
    ]
});
Usage:
  • .module toggle KillAura - Toggle a module
  • .module list Combat - List modules by category
  • .module info KillAura - Show module info

Accessing Command Arguments

The onExecute handler receives parameters in order:
registerCommand({
    name: "example",
    parameters: [
        { name: "first", required: true },
        { name: "second", required: false },
        { name: "rest", vararg: true }
    ],
    onExecute: (first, second, ...rest) => {
        // first - first parameter
        // second - second parameter (or undefined)
        // rest - array of remaining parameters
    }
});

Error Handling

Handle errors in command execution:
registerCommand({
    name: "risky",
    onExecute: () => {
        try {
            // Potentially failing code
            const player = mc.player;
            if (player === null) {
                throw new Error("Player is null");
            }
            // ...
        } catch (error) {
            Client.displayChatMessage("Error: " + error.message);
        }
    }
});

Best Practices

  1. Descriptive names - Use clear, intuitive command names
  2. Aliases - Provide short aliases for frequently used commands
  3. Auto-completion - Implement completions for better UX
  4. Validation - Validate inputs to prevent errors
  5. Error messages - Show helpful error messages
  6. Help text - Consider adding a help subcommand
  7. Null checks - Always check for null before using game objects

Next Steps

Build docs developers (and LLMs) love