Datapack discovery
The lifecycle API grants developers much more direct access to modifying some of the core parts of the server. One such core aspect are datapacks. No more asking users to download your datapack alongside the plugin — you can now include the datapack in your plugin JAR and load it yourself!
The datapack discovery lifecycle event
Section titled “The datapack discovery lifecycle event”The LifecycleEvents.DATAPACK_DISCOVERY
lifecycle
event allows developers to add, check for, and even remove datapacks which are about to be loaded by the server.
Retrieving all currently discovered datapacks
Section titled “Retrieving all currently discovered datapacks”For the sake of simplicity, let’s start with the most basic operation: Retrieving discovered data packs. For this, we can use the following simple code:
context.getLogger().info("The following datapacks were found: {}", String.join(", ", event.registrar().getDiscoveredPacks().keySet()));
This might yield the following log output:
[00:26:12 INFO]: [PaperDocsTestProject] The following datapacks were found: file/bukkit, minecart_improvements, paper, redstone_experiments, trade_rebalance, vanilla
This resulted in a few more datapacks than one might expect. Primarily, at the time of writing, the experimental minecart_improvements
, redstone_experiments
,
and trade_rebalance
datapacks. The datapack discovery does not care about whether a datapack should be enabled or not. It simply looks for datapacks that
the server could enable.
Removing discovered datapacks
Section titled “Removing discovered datapacks”You can very easily prevent datapacks from being discovered by calling DatapackRegistrar#removeDiscoveredPack(String name)
on the datapack’s name.
To remove the above-mentioned, experimental datapacks, you could the following code:
// The names of the datapacks we want to remove.final Set<String> datapacksToRemove = Set.of("minecart_improvements", "redstone_experiments", "trade_rebalance");
datapacksToRemove.forEach( // Iterate through every datapack and remove it from the discovered packs. datapack -> event.registrar().removeDiscoveredPack(datapack));
// The logging line from before.context.getLogger().info("The following datapacks were found: {}", String.join(", ", event.registrar().getDiscoveredPacks().keySet()));
This would, as expected, remove the entries from being logged (and thus discovered):
[00:35:39 INFO]: [PaperDocsTestProject] The following datapacks were found: file/bukkit, paper, vanilla
Registering custom datapacks
Section titled “Registering custom datapacks”The main use case of the datapack register lifecycle event is the adding of plugin included datapacks. And Paper makes this pretty simple: You have to include your datapack in the plugin’s JAR file, as already mentioned. This does not mean including the datapack zip. This means including the source files, which makes it very convenient to work with in a dev environment.
Including the datapack in your plugin
Section titled “Including the datapack in your plugin”Before you can let the server know about your datapack, you must first include it. For this, you can just add it to your plugins src/main/resources folder.
The datapack should have at least one extra folder (so don’t dump all the contents into the resources
root). For this example, it will be located under
resources/custom_datapack, but you can rename this second folder to any name you want to. If you have done everything correctly, you should have a folder structure,
which looks similar to this:
Directorysrc/main/resources
Directorycustom_datapack
- pack.mcmeta
Directorydata/
- …
Build your plugin and verify that there is a custom_datapack
folder in the root of your plugin’s JAR file.
Discovering the datapack
Section titled “Discovering the datapack”To discover the datapack, you must call the DatapackRegistrar#discoverPack(URI uri, String id)
method. The uri should point to your datapack’s folder in your JAR. This can be achieved simply by calling
getClass().getResource("/custom_datapack").toURI()
. The preceding slash is very important. The id can be set to
whatever you want to identify your datapack with. The final name of the loaded pack will be <YourPluginName>/<id>
.
Code example:
try { // Retrieve the URI of the datapack folder. URI uri = Objects.requireNonNull(getClass().getResource("/custom_datapack")).toURI(); // Discover the pack. Here, the id is set to "provided", which indicates to a server owner // that your plugin includes this data pack (as the name is prefixes with the plugin name). event.registrar().discoverPack(uri, "provided");} catch (URISyntaxException | IOException e) { throw new RuntimeException(e);}
Verifying that the datapack loaded correctly
Section titled “Verifying that the datapack loaded correctly”You can verify that a datapack loaded simply by executing the command /datapack list enabled
.
Alternatively, you can check for the loaded status of your datapack during normal execution
of your plugin. For example, a simple check inside your plugin’s onLoad
method might look like this:
public final class CustomJavaPlugin extends JavaPlugin {
@Override public void onLoad() { Datapack pack = this.getServer().getDatapackManager().getPack(getPluginMeta().getName() + "/provided"); if (pack != null) { if (pack.isEnabled()) { this.getLogger().info("The datapack loaded successfully!"); } else { this.getLogger().warn("The datapack failed to load."); } } }}
If everything has gone correctly, the console should contain output similar to this:
[01:10:12 INFO]: [PaperDocsTestProject] Loading server plugin PaperDocsTestProject v1.0-DEV[01:10:12 INFO]: [PaperDocsTestProject] The datapack loaded successfully!