Skip to content
CmdrDats edited this page Dec 30, 2012 · 2 revisions

Commands

(:require [cljminecraft.commands :as cmd])

Source: commands.clj

Description

The command framework in cljminecraft builds on top of the Bukkit commands, but implements a more succinct way of providing parameter types (for autocompletion and conversion) and has an open system for you to add your own.

It also automatically handles arity checking to make sure your function is passed the correct number of arguments as well as the correct types and gracefully dies on exceptions (ie, don't boot a player out of the server!) - See: http://wiki.bukkit.org/Plugin_Tutorial#Writing_a_safe_onCommand

Usage

First, you need to declare all your commands in your plugin.yml file as describes here: http://wiki.bukkit.org/Plugin_Tutorial#Adding_your_Command_to_the_Plugin.yml

Once you have that down you can create a function to handle the command and register it:

(defn give-money [sender receiver amount]
    {:msg (format "Taking %s money from %s and giving to %s" amount sender receiver)})

(cmd/register-command plugin "transfer" #'give-money :player :int)

You'll notice that the give-money function above returns a map {:msg ....}, this will automatically be seen as a response to the sender so that you don't need to explicitly send the sender the message with something like (respond sender ".."), thereby letting the framework decide whether it can actually respond or not and handle it gracefully.

register-command expects the plugin (which you obtain from your plugin's start function), the command name, a callback function and a variable number of argument types.

If any of the arguments are a vector, the first item will be the type and the second will be the finite options for tabcompletions, for instance: If you wanted a /server start|stop command, you'd write something like:

(cmd/register-command plugin "server" #'server [:keyword [:start :stop]])

Keywords are generally preferred if you're going to deal with it directly in code, but if you're going to use it for something a list of names:

(cmd/register-command plugin "strangecommand" #'strange [:string ["Bob" "Jim" "Mary"]])

Arguments types

The arguments for a command automatically convert to it's correct class, for instance, a :player argument will get to the command function as a Player object and similar for materials, entities, longs, ints and keyword

:player

:player as an argument will autocomplete and convert to any online player

:material

:material will autocomplete and convert to the corresponding MaterialData involved, see [Item functions](Item functions)

:event

:event will autocomplete to the string representation of any of the event types, see [Event handling](Event handling)

:entity

:entity will autocomplete and convert to any of the entity types, see [Entity handling](Entity handling)

:permission

:permission will autocomplete to any of the declared permissions (in the permission: and command: blocks) of all the plugins on the server.

others

The other types (:string, :long, :double, :int) don't autocomplete unless you provide it with a finite set, eg [:string ["Bob" "Joe"]] or [:int [1000 2000]]

Extending argument types

To extend the argument types to provide your own tab completion for your specific plugin is a matter of implementing two multimethods: cmd/convert-type and cmd/param-type-tabcomplete

Imagine you keep track of a list of players that are special in some way and you want to only autocomplete by that list, maybe special-players. You could do this:

(def special-players (atom #{}))

(defmethod cmd/convert-type :special-player [sender type arg]
  (if (contains? @special-players arg)
    (plr/get-player arg)))

(defmethod cmd/param-type-tabcomplete :special-player [sender type arg]
  (filter #(.startsWith % arg) @special-players))

That would let you (and every other clojure plugin) register a command using it like so:

(cmd/register-command plugin "lookup-special" #'lookup-special :special-player)

And you're done.