Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ProjectUnified/CraftCommand/llms.txt
Use this file to discover all available pages before exploring further.
ArgumentResolver<S, T> is a functional-style interface that teaches CraftCommand how to parse a custom type from command argument strings. Implement it for any type that CraftCommand does not handle out of the box, register the implementation with CommandManager.registerResolver() or CommandManager.registerProvider(), and the annotation processor will call it automatically wherever that type appears as a command parameter.
ArgumentResolver<S, T>
S is the platform sender type (e.g. Object for Standalone, CommandSender for Bukkit,
CommandSourceStack for Paper). T is the Java type this resolver produces.
resolve
The required method. Converts the current argument string — and optionally additional consecutive arguments whengetWidth() > 1 — into a value of type T.
The command sender executing or tab-completing the command.
When
When
getWidth() is 1: the full argument array for the command invocation; current is the
relevant entry at the current index.When
getWidth() is > 1: a sliced sub-array args[argIdx..argIdx+width) containing exactly
width entries. current is args[width - 1] (the last entry in the slice).The argument string at the current resolution index. For single-width resolvers this is always
equal to
args[index]. Throw any exception — including CommandException — to signal a
resolution failure; the error handler will receive it.T.
suggest
Provides tab-completion candidates for this parameter. The default implementation returns an empty list. The candidates you return are passed throughCommandManager.filterSuggestions() before
being sent to the client, so you can return the full set and rely on prefix filtering to narrow it.
The command sender requesting tab completion.
All arguments entered so far (same slicing rules as
resolve).The partial argument string typed at the current position.
List<String> of suggestion candidates, or an empty list if none apply.
getWidth
Returns the number of consecutive arguments this resolver consumes. The default is1. When you
return a value greater than 1, CommandManager.resolveParameter() passes a sub-array of exactly
width entries to resolve() and advances indexHolder[0] by width.
1 for all single-argument types.
ArgumentResolverProvider<S>
ArgumentResolverProvider<S> is a factory that CommandManager consults at runtime when no exact
or hierarchy match is found in the registered resolver map. It is the right tool for entire class
families — enums, sealed types, interface hierarchies — where registering every concrete class
individually would be impractical.
getResolver
The target class that
CommandManager.getResolver() is trying to resolve. Inspect it (e.g.
type.isEnum()) to decide whether this provider can handle it.type, or null if this provider does not handle it. CommandManager
tries providers in registration order and uses the first non-null result.
Enum provider example
@Command-annotated class is automatically
resolved from the argument string without a dedicated registerResolver call per enum type.
Multi-argument resolvers
When a logical parameter spans more than one raw argument (e.g. a 2D point expressed as<x> <y>),
override getWidth() to return the number of arguments you need.
CommandManager.resolveParameter() uses the width to:
- Verify that at least
widtharguments remain before callingresolve(); throwsCommandExceptionwith the"missing-argument"key otherwise. - Slice
args[argIdx..argIdx+width)and pass the sub-array asargstoresolve().currentissubArgs[width - 1](the last item in the slice). - Advance
indexHolder[0]bywidthso the next parameter starts at the correct position.
Complete Point resolver example
Point automatically consumes the
next two tokens from the argument list. A third parameter following the Point in the same method
receives the argument at index + 2.
The
suggest() method receives the same sliced sub-array as resolve(), so you can inspect
args[0] to determine which coordinate position is currently being typed and return appropriate
suggestions.Resolver registration order & priority
CommandManager.getResolver(Class<T> type) walks the following priority order, stopping at the
first match:
- Parameter-level
@Resolvemethod with an explicit name — a local resolver method on the command class annotated@Resolve("resolverName")where the name matches the@Paramdeclaration. Evaluated by the generated wrapper before calling the manager. - Implicit local
@Resolvemethod matching return type — a local resolver method whose return type matches the parameter type, with no explicit name required. Also evaluated by the generated wrapper. registerResolver()exact type match — the type passed toregisterResolverequalstypeexactly (resolvers.get(type) != null).registerResolver()class hierarchy match — any registered keyKwhereK.isAssignableFrom(type)istrue(superclass or interface). Iterates the resolver map in arbitrary order; register the most specific type explicitly when ambiguity is possible.registerProvider()dynamic match — providers are queried in registration order; the first non-null result wins.- Sender-type fallback — if none of the above matched, a synthetic resolver is returned that
casts the sender to
Tiftype.isInstance(sender), or throwsIllegalArgumentException.
Built-in type resolvers
The following types are handled at compile time by the annotation processor’sTypeSupport class.
You do not need to call registerResolver for them — the processor emits inline parsing code
directly into the generated wrapper.
| Type | Parse method |
|---|---|
String | Direct assignment |
int / Integer | Integer.parseInt() |
long / Long | Long.parseLong() |
double / Double | Double.parseDouble() |
float / Float | Float.parseFloat() |
boolean / Boolean | Boolean.parseBoolean() (validates "true"/"false") |
short / Short | Short.parseShort() |
byte / Byte | Byte.parseByte() |
char / Character | Single-character validation + charAt(0) |
Bukkit / Paper platform types
The Bukkit and Paper processors extendTypeSupport with the following additional built-in
resolutions that are emitted as inline helper-method calls in the generated wrapper:
| Type | Resolution |
|---|---|
org.bukkit.entity.Player | Bukkit.getPlayer(name) — throws if not online |
org.bukkit.OfflinePlayer | Bukkit.getOfflinePlayer(name) — throws IllegalArgumentException if hasPlayedBefore() is false |
org.bukkit.World | Bukkit.getWorld(name) — throws if not found |
org.bukkit.Location | 4-argument parse: world x y z (width = 4) |
org.bukkit.command.CommandSender and io.papermc.paper.command.brigadier.CommandSourceStack
are not listed here because they are not registered as built-in platform types. Instead they
are handled by the sender-type fallback (step 6 of the resolver lookup): when a parameter type
is assignment-compatible with the platform sender, the sender itself is cast and returned without
consuming any argument token.Tab-completion for
Player and World is also generated automatically: the wrapper emits calls
to private suggestPlayers() and suggestWorlds() helper methods that filter online player
names and loaded world names respectively.