Every command parameter except the sender is resolved from the user’s raw string input through anDocumentation 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> instance. Resolution happens inside the generated wrapper class: for each argument position the wrapper calls either a built-in parse expression (for the 17 JDK types registered in TypeSupport) or delegates to manager.resolveParameter(...) for custom types. This design keeps your command method signatures clean — you declare Point pt and receive a fully-constructed Point, never a raw String.
Built-in type support
TypeSupport maintains a registry of JDK types that are resolved inline without any registered ArgumentResolver. These 17 types (primitives and their wrappers) are handled by the processor at code-generation time, emitting direct parse calls such as Integer.parseInt(arg) rather than going through the manager:
| Type | Primitive | Wrapper |
|---|---|---|
| String | — | java.lang.String |
| Integer | int | java.lang.Integer |
| Long | long | java.lang.Long |
| Double | double | java.lang.Double |
| Float | float | java.lang.Float |
| Short | short | java.lang.Short |
| Byte | byte | java.lang.Byte |
| Character | char | java.lang.Character |
| Boolean | boolean | java.lang.Boolean |
TypeSupport to add platform-specific types. For example, a Bukkit processor registers org.bukkit.entity.Player, org.bukkit.World, and org.bukkit.Location so they can be declared as parameters in the same way.
Global resolvers
For any type not inTypeSupport, you register an ArgumentResolver with the manager before registering commands. Global resolvers are available to every command managed by that CommandManager instance.
Point parameter automatically receives a constructed Point object with both coordinates parsed from the input.
ArgumentResolver interface
ArgumentResolver<S, T> is the core abstraction. It has three methods:
getWidth() is the key to multi-argument resolution. When the generated wrapper calls manager.resolveParameter(...), the manager reads resolver.getWidth(), extracts args[index..index+width] as a sub-array, passes it to resolve(), and advances the shared indexHolder by width. This ensures the next parameter starts reading from the correct position.
Dynamic provider matching
ArgumentResolverProvider<S> lets you handle entire type families — for example, all enum types — without registering a resolver for each one individually.
enum is resolved automatically. The getResolver(Class<T>) method in CommandManager checks providers after exhausting exact-type and hierarchy matches.
Local resolvers via @Resolve
A method inside the command class annotated with@Resolve becomes a local resolver — a per-instance resolver that takes priority over global ones. The processor finds these methods at compile time and emits direct method calls in the generated wrapper rather than delegating to the manager.
Implicit binding — a @Resolve method is matched by return type. If the method’s return type equals a parameter type, the processor wires them together automatically:
@Resolve("methodName") on a parameter overrides the implicit match and selects the named method regardless of return type compatibility:
@Resolve method defined in the root command class is visible from any nested @Subcommand class in the same hierarchy:
@Resolve method for the same type to override the parent’s resolver:
Resolver lookup priority
When the generated wrapper needs to resolve a parameter, the processor usesResolverLookup at compile time (for local resolvers) and CommandManager.getResolver() at runtime (for global resolvers). The effective priority order is:
- Local
@Resolvemethod with explicit name — parameter carries@Resolve("methodName"); the named method is used directly. - Implicit local
@Resolvemethod by type — a@Resolve-annotated method in the command class (or its enclosing parent class) whose return type matches the parameter type. - Exact-type global resolver — registered via
manager.registerResolver(ExactType.class, resolver). - Class hierarchy / interface match in global resolvers — if no exact match is found,
getResolver()scans all registered entries for one whose keyisAssignableFrom(requestedType). - Dynamic provider match —
ArgumentResolverProvider.getResolver(type)is called for each registered provider in registration order; the first non-null result wins. - Sender fallback — if the requested type is assignable from the actual sender object, the sender is returned directly. This is used for parameters that should receive the sender itself rather than a separate resolved value.
Multi-argument resolvers
WhengetWidth() returns a value greater than 1, the resolver consumes that many consecutive arguments from the input array. The CommandManager.resolveParameter() method slices args[index..index+width] and passes the sub-array to resolve(), then advances indexHolder[0] by width. Subsequent parameters continue reading from the updated index, so argument positions remain correct throughout the method:
String parameter works as expected: