Modules & packages
Maven modules
| Module | Artifact id | Contents |
|---|---|---|
Lib/API | Lib-API | Public interfaces and abstractions |
Lib/src | paper-dispatch | Implementation, bundles Lib-API |
Exemple-Plugin | — | Example plugin, not published |
Depend on paper-dispatch. See
Add the dependency for the coordinates —
note the group id differs from the single-module default.
Packages
Everything lives under fr.robie.paperdispatch.
| Package | Key types |
|---|---|
command | BaseCommand, SubCommand, CommandDispatch, CommandResultType |
manager | ICommandManager, CommandManager |
flag | Flags, Flag, BoolFlag, ValueFlag, FlagContext |
argument | EnumArgument, OfflinePlayerArgument |
requirement | CommandRequirement, PermissionRequirement, PlayerOnlyRequirement |
cache | OfflinePlayerCache |
logger | PluginLogger |
ICommandManager
The contract, minus deprecated members:
<Y extends Plugin> void trackCommand(BaseCommand<Y> command);
<U extends Plugin> BaseCommand<U> trackCommand(BaseCommand.BaseCommandBuilder<U> builder);
void flushRegistrations();
<Y extends Plugin> void unregisterCommand(BaseCommand<Y> command);
void unregisterCommands(Collection<? extends BaseCommand<?>> toRemove);
void unregisterReloadableCommands();
void unregisterAll(Plugin plugin);
void unregisterAll();
boolean isRegistered(Plugin plugin, String name);
boolean isRegistered(BaseCommand<?> command);
List<BaseCommand<?>> getCommands(Plugin plugin);
CommandManager is safe to call from async contexts — it uses a
ConcurrentHashMap plus CopyOnWriteArrayList, and hops onto the global region
scheduler for the server-global command refresh, which must run on the main
thread.
Requirements
CommandRequirement<T extends Plugin> has a single method:
boolean isMet(T plugin, CommandSourceStack source);
Two implementations ship: PermissionRequirement and PlayerOnlyRequirement.
Add your own with addRequirement(...) on the builder.
Offline player cache
Optional UUID ↔ name cache backing OfflinePlayerArgument's tab-completion.
OfflinePlayerCache.install(this); // onEnable
OfflinePlayerCache.uninstall(this); // onDisable — shuts down its HttpClient
Or own the lifecycle yourself:
OfflinePlayerCache cache = OfflinePlayerCache.builder(this)
.maximumSize(5000)
.maxSuggestions(50)
.expireAfterAccess(Duration.ofMinutes(10))
.buildAndRegister();
cache.close(); // onDisable
Everything degrades gracefully without a cache installed: commands still work, they just do not complete player names.
Each cache owns an HttpClient with its own selector and executor threads, so a
reload-heavy server leaks a thread pool per reload if you never close it.
Its global instance is also static — which is why
relocation is mandatory when you shade the
library.
Suggestions are capped
The name index is unbounded, so an empty prefix would otherwise serialise every
known player name on every keystroke. maxSuggestions bounds it.