Getting Started with Paper
Why Choose Paper?
Paper offers several advantages over standard Bukkit/Spigot servers:
- Improved performance - Paper includes numerous optimizations to improve server performance
- Enhanced API - Paper extends the Bukkit/Spigot API with additional features
- Better stability - Many bug fixes and improvements for a more stable server
- Active development - Regular updates and a responsive development team
- Bukkit/Spigot compatibility - Most Bukkit/Spigot plugins work on Paper without modification
Setting Up Your Development Environment
Setting up for Paper development is similar to Bukkit/Spigot, with a few differences:
- Install Java Development Kit (JDK) 17 or higher
Paper requires JDK 17 or higher for the latest versions. Download it from Adoptium or Oracle.
- Choose an IDE
We recommend IntelliJ IDEA or Eclipse for Java development.
- Set up a build system
Maven or Gradle are recommended for managing dependencies and building your plugin.
- Add the Paper API
Instead of using the Spigot API, use the Paper API as your dependency:
pom.xml (Paper API Dependency)123456789101112<!-- Maven --> <repository> <id>papermc</id> <url>https://repo.papermc.io/repository/maven-public/</url> </repository> <dependency> <groupId>io.papermc.paper</groupId> <artifactId>paper-api</artifactId> <version>1.20.4-R0.1-SNAPSHOT</version> <scope>provided</scope> </dependency>
Or for Gradle:
build.gradle (Paper API Dependency)12345678910// Gradle repositories { maven { url = uri("https://repo.papermc.io/repository/maven-public/") } } dependencies { compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT") }
Paper-Specific Features
Enhanced Event API
Paper adds new events and enhances existing ones. Here's an example of using a Paper-specific event:
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.Component;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class ChatListener implements Listener {
@EventHandler
public void onPlayerChat(AsyncChatEvent event) {
// Paper uses Adventure API for text components
Component message = event.message();
// Modify the message
Component newMessage = Component.text("[Modified] ").append(message);
event.message(newMessage);
// This event is async, so be careful with what you do here
}
}
Adventure API
Paper uses the Adventure API for text components, which provides a more powerful way to create rich text:
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import org.bukkit.entity.Player;
public void sendFancyMessage(Player player) {
Component message = Component.text("Click me!")
.color(NamedTextColor.GOLD)
.decorate(TextDecoration.BOLD)
.hoverEvent(HoverEvent.showText(Component.text("Click to open website")))
.clickEvent(ClickEvent.openUrl("https://papermc.io"));
player.sendMessage(message);
}
Asynchronous API
Paper provides more async APIs to help improve server performance:
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public class AsyncExample extends JavaPlugin {
public void teleportPlayerAsync(Player player, Location location) {
// Load the chunk asynchronously before teleporting
World world = location.getWorld();
int chunkX = location.getBlockX() >> 4;
int chunkZ = location.getBlockZ() >> 4;
world.getChunkAtAsync(chunkX, chunkZ).thenAccept(chunk -> {
// Now that the chunk is loaded, teleport the player (on the main thread)
getServer().getScheduler().runTask(this, () -> {
player.teleport(location);
player.sendMessage("Teleported to pre-loaded chunk!");
});
});
}
}
Best Practices for Paper Plugins
Compatibility Considerations
When developing for Paper, consider these best practices:
- Check for Paper - If using Paper-specific features, check if the server is running Paper
- Fallback implementations - Provide fallbacks for Bukkit/Spigot servers when possible
- Use Adventure API - Leverage the Adventure API for text components
- Async where possible - Use Paper's async APIs to improve performance
Example of checking if the server is running Paper:
public boolean isPaperServer() {
try {
Class.forName("io.papermc.paper.event.player.AsyncChatEvent");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
Paper Configuration
Paper adds many server configuration options that can affect your plugin:
- paper-global.yml - Global settings that affect all worlds
- paper-world-defaults.yml - Default settings for all worlds
- paper-world/<world>.yml - Settings for specific worlds
Be aware of these configurations as they might affect your plugin's behavior. For example, some events might be disabled or modified by Paper's configuration.
Paper API Extensions
Paper extends many Bukkit/Spigot classes with additional methods. Here are some examples:
// Paper-specific methods on Player
Player player = event.getPlayer();
// Get the player's client brand (what client they're using)
String clientBrand = player.getClientBrandName();
// Check if the player is in a vehicle
boolean inVehicle = player.isInsideVehicle();
// Get the player's locale
String locale = player.locale().toString();
// Paper-specific methods on World
World world = player.getWorld();
// Get the world's spawn location with yaw and pitch
Location spawnLocation = world.getSpawnLocation();
// Check if a chunk is generated
boolean isChunkGenerated = world.isChunkGenerated(chunkX, chunkZ);