FAQ
Short answers to the questions that come up before you write code.
Does it work on Spigot or Bukkit?
No, and there is no fallback. It compiles against paper-api and uses Paper's
Brigadier Commands API, CommandSourceStack, LifecycleEventManager and
paper-plugin.yml ā none of which exist elsewhere. See
Supported platforms.
Does it work on Folia?
Untested, so it is not listed as supported. The command manager already hops to the global region scheduler for the server-wide command refresh, which is the part that must run on the right thread ā but nobody has verified the rest.
Do I have to shade it?
Yes. It is a library, not a plugin, so nothing on the server provides it at
runtime ā compileOnly alone gives you NoClassDefFoundError on first use. And
it must be relocated while you shade, because OfflinePlayerCache's global
instance is static. See
Shading & relocation.
Which artifact do I depend on?
paper-dispatch unless you have a reason not to ā it is the full implementation
and bundles Lib-API. Take Lib-API alone only when you want to compile
against the interfaces. Note the group id is com.github.1robie.paper-dispatch,
not com.github.1robie;
the dependency page explains why.
What Java version?
Java 21 ā the library is built with --release 21.
Argument, or flag?
Positional data is an argument; a modifier is a flag. If leaving it out should still run the command, it is an optional argument or a flag. Flags are also far more expensive: one Brigadier node per ordered subset of the flag set, versus roughly one node for an argument. Arguments has the full comparison.
How many flags is too many?
More than four and the library logs a warning at startup with the node count. At
five flags a single command's flag subtree is already ~325 nodes, and that tree
is sent to every joining client. Prefer one value flag carrying several options
ā Flags.stringFlag("mode").suggests("fast", "safe") ā over four booleans.
Raise or silence the threshold with setFlagCountWarnThreshold(...) once you
have measured the cost.
Why doesn't perform run when an argument is missing?
Because a required argument is part of the Brigadier path. Without it the command does not match at all, so there is nothing to handle. If you want to handle absence, make it an optional argument.
resolvePlayer or getSenderAsPlayer?
resolvePlayer("target") reads the argument named target.
getSenderAsPlayer() returns whoever typed the command. They both return a
Player and are otherwise unrelated ā this is the most common mix-up with the
API. The usual "me, or someone I name" shape is:
Player target = dispatch.resolvePlayer("target")
.orElse(dispatch.getSenderAsPlayer());Can I register commands from a PluginBootstrap?
Not today. BaseCommand<T extends Plugin> needs a plugin instance at
construction, and PluginBootstrap#bootstrap runs before createPlugin. That
matters only if you need datapack command functions to see your commands ā
register those directly against context.getLifecycleManager() and use this
library for everything else.
Do I need the offline player cache?
Only for offline-player tab-completion. Everything else works without it, and
OfflinePlayerArgument degrades to rejecting values rather than crashing. See
Offline player cache.
Where is the Javadoc?
Linked here, but it does not resolve for 1.0.2 ā that release predates the source and Javadoc jars being wired into the build. The next release will have it.
Which version do these docs describe?
1.0.3, which is not released yet. The current release is 1.0.2 and the
registration API differs ā trackCommand, flushRegistrations,
getSenderAsPlayer and resolvePlayer do not exist there.
Migrating maps the old names to the new.
Something is not answered here
Troubleshooting covers concrete failures. Beyond that, open an issue on the repository.
Last updated on