Quick Start - Create a PaperMC Plugin with Reedwork
This guide creates a complete PaperMC plugin using Reedwork and demonstrates the core framework workflow.
The example demonstrates the main Reedwork workflow:
- automatic component discovery;
- dependency injection;
- event listener registration;
- annotation-based commands;
- custom enchantment registration.
The complete example is designed to work together as a single plugin.
1. Create the plugin
Section titled “1. Create the plugin”Start with a normal Paper plugin and initialize Reedwork in your main plugin class.
package dev.reedworkmc.examples.quickstart;
import dev.reedworkmc.reedwork.Reedwork;import org.bukkit.plugin.java.JavaPlugin;
public final class QuickstartExample extends JavaPlugin {
@Override public void onEnable() { // Plugin startup logic Reedwork.create(this) .scan("dev.reedworkmc.examples.quickstart"); }}The scan(...) call tells Reedwork which package contains your plugin components.
During scanning, Reedwork discovers managed classes such as commands, event listeners, services, and enchantments.
2. Enable bootstrap scanning
Section titled “2. Enable bootstrap scanning”Custom enchantments are registered during Paper’s bootstrap lifecycle.
The plugin therefore needs a bootstrapper:
package dev.reedworkmc.examples.quickstart;
import dev.reedworkmc.reedwork.Reedwork;import io.papermc.paper.plugin.bootstrap.BootstrapContext;import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
class QuickstartExampleBootstrap implements PluginBootstrap {
@Override public void bootstrap(final BootstrapContext context) { // Plugin bootstrap logic Reedwork.bootstrap(context).scan("dev.reedworkmc.examples.quickstart"); }}The bootstrapper initializes Reedwork for the Paper registry phase.
The package scan is the same as in the normal plugin lifecycle, allowing Reedwork to discover registry-backed components before the server starts.
Your paper-plugin.yml needs to reference the bootstrapper:
name: QuickstartExampleversion: '${version}'
main: dev.reedworkmc.examples.quickstart.QuickstartExamplebootstrapper: dev.reedworkmc.examples.quickstart.QuickstartExampleBootstrapapi-version: '26.2'load: POSTWORLD3. Add a service with dependency injection
Section titled “3. Add a service with dependency injection”Reedwork components can receive dependencies through their constructors.
The example uses a singleton service that creates a reusable item:
package dev.reedworkmc.examples.quickstart.services;
import dev.reedworkmc.reedwork.annotation.Singleton;import org.bukkit.Material;import org.bukkit.enchantments.Enchantment;import org.bukkit.inventory.ItemStack;import org.bukkit.inventory.meta.ItemMeta;
@Singletonpublic final class ReedworkItemManager {
private final ItemStack reedworkItem = createReedworkItem();
private ItemStack createReedworkItem() { ItemStack reedworkItem = new ItemStack(Material.PAPER); ItemMeta meta = reedworkItem.getItemMeta();
Enchantment reedworkEnchantment = Enchantment.getByName("reedwork"); meta.addEnchant(reedworkEnchantment, 1, false);
reedworkItem.setItemMeta(meta); return reedworkItem; }
public ItemStack getReedworkItem() { return reedworkItem.clone(); }}The @Singleton annotation tells Reedwork to create one shared instance.
The service is injected into both the command and the event listener.
No manual object creation or dependency passing is required.
4. Create an event listener
Section titled “4. Create an event listener”Events use the normal Bukkit/Paper event API.
The only Reedwork-specific part is the @EventListener annotation:
package dev.reedworkmc.examples.quickstart.events;
import dev.reedworkmc.examples.quickstart.services.ReedworkItemManager;import dev.reedworkmc.reedwork.annotation.EventListener;import org.bukkit.event.EventHandler;import org.bukkit.event.Listener;import org.bukkit.event.player.PlayerJoinEvent;
@EventListenerpublic class PlayerJoinServerEvent implements Listener {
private final ReedworkItemManager reedworkItemManager;
public PlayerJoinServerEvent(ReedworkItemManager reedworkItemManager) { this.reedworkItemManager = reedworkItemManager; }
@EventHandler public void onPlayerJoin(PlayerJoinEvent event) { event.getPlayer().getInventory().addItem(reedworkItemManager.getReedworkItem()); }}When Reedwork scans the package, it creates the listener, resolves its constructor dependencies, and registers it automatically with Paper.
5. Create an annotation-based command
Section titled “5. Create an annotation-based command”Commands are defined as regular Java classes.
package dev.reedworkmc.examples.quickstart.commands;
import dev.reedworkmc.examples.quickstart.services.ReedworkItemManager;import dev.reedworkmc.reedwork.annotation.Command;import dev.reedworkmc.reedwork.annotation.CommandHandler;import dev.reedworkmc.reedwork.annotation.SubCommand;import dev.reedworkmc.reedwork.command.CommandContext;import org.bukkit.entity.Player;
@Command( value = "helloreedwork", description = "Send a welcome message to a player", permission = "quickstart.command.hello", cooldown = 10, aliases = {"hellorw", "hrw"})public final class HelloCommand {
private final ReedworkItemManager reedworkItemManager;
public HelloCommand(ReedworkItemManager reedworkItemManager) { this.reedworkItemManager = reedworkItemManager; }
@CommandHandler public boolean addReedworkItem(CommandContext context) { context.player().getInventory().addItem(reedworkItemManager.getReedworkItem()); return true; }
@SubCommand("<target>") public boolean addReedworkItemToTarget(CommandContext context, Player target) { target.getInventory().addItem(reedworkItemManager.getReedworkItem()); return true; }}The @Command annotation defines the command metadata.
@CommandHandler creates the default command action, while @SubCommand creates additional command paths.
Command parameters such as Player are resolved automatically by Reedwork.
The same ReedworkItemManager service is injected into the command.
6. Register a custom enchantment
Section titled “6. Register a custom enchantment”Custom enchantments are regular Java classes implementing CustomEnchantment.
package dev.reedworkmc.examples.quickstart.enchantments;
import dev.reedworkmc.reedwork.annotation.Enchantment;import dev.reedworkmc.reedwork.enchantment.CustomEnchantment;import io.papermc.paper.registry.data.EnchantmentRegistryEntry;import io.papermc.paper.registry.keys.ItemTypeKeys;import io.papermc.paper.registry.keys.tags.ItemTypeTagKeys;import io.papermc.paper.registry.tag.TagKey;import net.kyori.adventure.key.Key;import net.kyori.adventure.text.Component;import org.bukkit.inventory.EquipmentSlotGroup;import org.bukkit.inventory.ItemType;
@Enchantment("reedwork")public class ReedworkEnchantment implements CustomEnchantment {
@Override public Component description() { return Component.text("Reedwork"); }
@Override public TagKey<ItemType> supportedItems() { return ItemTypeTagKeys.ENCHANTABLE_DURABILITY; }
@Override public int anvilCost() { return 1; }
@Override public int maxLevel() { return 1; }
@Override public int weight() { return 1; }
@Override public EnchantmentRegistryEntry.EnchantmentCost minimumCost() { return EnchantmentRegistryEntry.EnchantmentCost.of(1, 5); }
@Override public EnchantmentRegistryEntry.EnchantmentCost maximumCost() { return EnchantmentRegistryEntry.EnchantmentCost.of(1, 10); }
@Override public EquipmentSlotGroup activeSlots() { return EquipmentSlotGroup.ANY; }}The @Enchantment annotation defines the registry key.
During the Paper bootstrap phase, Reedwork discovers the enchantment and creates the corresponding registry entry.
No manual registry code is required.
How the example works
Section titled “How the example works”The final dependency and registration flow looks like this:
QuickstartExample├── Reedwork scanning├── HelloCommand│ └── ReedworkItemManager├── PlayerJoinServerEvent│ └── ReedworkItemManager└── ReedworkEnchantmentThe plugin only declares the components it needs.
Reedwork handles:
- discovering classes
- creating components
- resolving dependencies
- registering listeners
- registering commands
- integrating enchantments into Paper’s registry system
Next steps
Section titled “Next steps”This quick start showed the complete Reedwork workflow.
Continue with the individual guides to learn each feature in detail:
The complete runnable example is available in the ReedworkExamples repository.