Skip to content

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.

Start with a normal Paper plugin and initialize Reedwork in your main plugin class.

QuickstartExample.java
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.

Custom enchantments are registered during Paper’s bootstrap lifecycle.

The plugin therefore needs a bootstrapper:

QuickstartExampleBootstrap.java
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:

paper-plugin.yml
name: QuickstartExample
version: '${version}'
main: dev.reedworkmc.examples.quickstart.QuickstartExample
bootstrapper: dev.reedworkmc.examples.quickstart.QuickstartExampleBootstrap
api-version: '26.2'
load: POSTWORLD

3. 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:

ReedworkItemManager.java
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;
@Singleton
public 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.

Events use the normal Bukkit/Paper event API.

The only Reedwork-specific part is the @EventListener annotation:

PlayerJoinServerEvent.java
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;
@EventListener
public 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.

Commands are defined as regular Java classes.

HelloCommand.java
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.

Custom enchantments are regular Java classes implementing CustomEnchantment.

ReedworkEnchantment.java
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.

The final dependency and registration flow looks like this:

QuickstartExample
├── Reedwork scanning
├── HelloCommand
│ └── ReedworkItemManager
├── PlayerJoinServerEvent
│ └── ReedworkItemManager
└── ReedworkEnchantment

The 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

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.