Skip to Content
1robie

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

On this page