Plugin API¶
This page explains where new code plugs in. Every module follows the same
shape: a package under com.jruk8.jtemplate.core, its own config class (or
section), and a registrar implementing Bootstrap that is invoked from
JTemplatePlugin.setupCoreModules().
Dependencies flow one way, constructor-injected: configs -> services -> commands/placeholders. There are no singletons or static state.
Add a Command¶
Commands are Paper-native Brigadier nodes registered through
LifecycleEvents.COMMANDS (see CommandsRegistrar).
- Create a package
core.commands.user.<name>(oradmin, orspeed) with a command class exposing anode()method:
public class PingCommand {
private final CommandContext ctx;
public PingCommand(CommandContext ctx) { this.ctx = ctx; }
public LiteralArgumentBuilder<CommandSourceStack> node() {
return Commands.literal("ping")
.requires(CommandContext.requiresPermission("jflyspeed.ping"))
.executes(context -> {
ctx.sendMessage(context.getSource(), "<green>Pong!</green>");
return Command.SINGLE_SUCCESS;
});
}
}
-
Register it in the matching registrar (
UserCommandsRegistrar.register()):root.then(new PingCommand(ctx).node()); -
Declare the permission in
paper-plugin.ymland document the command indocs/commands.mdanddocs/permissions.md. Add aHelpEntryinHelpCommandso/jflyspeed helplists it.
Add a Config Option¶
The config classes are okaeri-configs. For a small option, add a field to an
existing config class; for a coherent new section, add a nested static class
and give it a field in the parent (see PluginConfig.Speed for the
pattern). The section will be created in the yaml file automatically and
reloaded by ConfigRegistrar on /jflyspeed reload.
Add a Stat to the Database¶
SqliteStorage exposes four operations for generic key/value counters:
increment(key, player)andincrementGlobal(key)per-player / globalplayerTotal(key, player)andglobalTotal(key)reads
Give your feature its own stat key and a small service class around
SqliteStorage (like CommandUsageTracker), then inject that service where
state is produced (command) and consumed (placeholder).
Add a Placeholder¶
Add a branch to SpeedUsageExpansion.onRequest():
Provider the value through an injected service and store it in SQLite if it
should survive restarts. Registered placeholders are announced to
PlaceholderAPI via getPlaceholders().
Remove the Placeholders Feature¶
If you do not need PAPI in your plugin:
- Delete the
core.placeholderspackage. - Remove the usage tracker wiring in
JTemplatePlugin(setupStorageAndPlaceholders()and theCommandsRegistrarargument). - Remove
PlaceholderAPIfrompaper-plugin.yml(dependencies), or keep it if your messages use%otherplugin_...%placeholders.
Modules Reference¶
| Package | Key classes |
|---|---|
core.commands |
CommandsRegistrar, UserCommandsRegistrar, AdminCommandsRegistrar, SpeedCommandsRegistrar, CommandContext |
core.commands.speed |
FlySpeedCommand, WalkSpeedCommand, SpeedCommand, FlyCommand, SpeedArgumentNodes, SpeedService, SpeedExecutor, FlyExecutor, SpeedValues, SpeedType, TargetSelector, SelectorSuggestions, ValueSuggestions |
core.configs |
ConfigRegistrar, PluginConfig |
core.messages |
MessageBootstrap, Messenger, MessageParser |
core.sounds |
SoundPlayer, SoundsConfig |
core.placeholders |
PlaceholdersBootstrap, CommandUsageTracker, SpeedUsageExpansion |
core.storage |
StorageBootstrap, SqliteStorage |
core.update |
UpdateCheckerBootstrap, UpdateCheckService, GitHubReleaseHttp, UpdateCheckNotifier, UpdateCheckJoinListener |