### Example plugin.yml file Source: https://docs.papermc.io/paper/dev/plugin-yml A standard example of a plugin.yml file structure. ```yaml name: ExamplePlugin version: 1.0.0 main: io.papermc.testplugin.ExamplePlugin description: An example plugin author: PaperMC website: https://papermc.io api-version: '26.1.2' ``` -------------------------------- ### YAML Configuration Example Source: https://docs.papermc.io/paper/dev/plugin-configurations An example of a basic YAML structure for plugin configuration. ```yaml root: one-key: 10 another-key: David ``` -------------------------------- ### PlayerCount Example Source: https://docs.papermc.io/paper/dev/plugin-messaging Java example demonstrating how to send a 'PlayerCount' plugin message and handle the response. ```APIDOC ## PlayerCount Plugin Message This section provides a Java code example for using the `PlayerCount` plugin message type. ### Method POST (via Plugin Message) ### Endpoint `BungeeCord` channel ### Request Body Example (for sending PlayerCount) ```java // Assuming 'player' is a valid Player object and 'out' is a ByteArrayDataOutput // Initialize ByteArrayDataOutput and write UTF strings out.writeUTF("PlayerCount"); out.writeUTF("lobby"); // Specify the server name player.sendPluginMessage(this, "BungeeCord", out.toByteArray()); ``` ### Response Example (handling PlayerCount response) ```java // Inside onPluginMessageReceived method if (channel.equals("BungeeCord")) { ByteArrayDataInput in = ByteStreams.newDataInput(message); String subchannel = in.readUTF(); if (subchannel.equals("PlayerCount")) { String server = in.readUTF(); int playerCount = in.readInt(); // Use the server name and player count as needed } } ``` ### Request Example ```java // Sending the PlayerCount request Player player = ...; // Get the player object ByteArrayDataOutput out = ByteStreams.newDataOutput(); out.writeUTF("PlayerCount"); out.writeUTF("lobby"); // The server to query player.sendPluginMessage(this, "BungeeCord", out.toByteArray()); ``` ### Response #### Success Response (handled in `onPluginMessageReceived`) - **server** (string) - The name of the server queried. - **playerCount** (int) - The number of players on the specified server. #### Response Example ```json { "server": "lobby", "playerCount": 42 } ``` ``` -------------------------------- ### Basic Suggestion Implementation Source: https://docs.papermc.io/paper/dev/command-api/basics/argument-suggestions A minimal example of implementing the suggests method using a lambda. This example does not provide any actual suggestions. ```java Commands.argument("name", StringArgumentType.word()) .suggests((ctx, builder) -> builder.buildFuture()); ``` -------------------------------- ### Console Output Example Source: https://docs.papermc.io/paper/dev/lifecycle/datapacks Expected console output when a datapack is successfully loaded. ```text [01:10:12 INFO]: [PaperDocsTestProject] Loading server plugin PaperDocsTestProject v1.0-DEV [01:10:12 INFO]: [PaperDocsTestProject] The datapack loaded successfully! ``` -------------------------------- ### Shapeless Recipe Crafting Examples Source: https://docs.papermc.io/paper/dev/recipes Illustrative examples of how items can be arranged in the crafting grid for a shapeless recipe. Any valid combination of the specified items will yield the result. ```plaintext DSS | SDS | S D D | D | D D | D | D S ``` -------------------------------- ### Define translation keys Source: https://docs.papermc.io/paper/dev/component-api/i18n Example of a properties file entry for a translation key with a placeholder. ```properties some.translation.key=Translated Message: {0} ``` -------------------------------- ### Start server with remote debugging enabled Source: https://docs.papermc.io/paper/dev/debugging Include the JDWP agent arguments in the server startup command to allow an IDE to attach to the running process. ```bash java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar paper-26.1.2.jar nogui ``` -------------------------------- ### Example event handler for debugging Source: https://docs.papermc.io/paper/dev/debugging A sample event handler used to demonstrate setting breakpoints and inspecting variables during execution. ```java @EventHandler public void onPlayerMove(PlayerMoveEvent event) { Player player = event.getPlayer(); Location location = player.getLocation(); if (location.getWorld() == null) return; if (location.getWorld().getEnvironment() == World.Environment.NETHER) { player.sendMessage("You are in the nether!"); } } ``` -------------------------------- ### BasicImplementation Example Source: https://docs.papermc.io/paper/dev/command-api/basics/custom-arguments A simple implementation of the CustomArgumentType interface that parses unquoted strings. ```APIDOC ## A very basic implementation ### Description This section provides a basic example of implementing the `CustomArgumentType` interface. It demonstrates how to parse an unquoted string and specifies `String` as both the custom type and the native type. ### Code Example ```java package io.papermc.commands; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import io.papermc.paper.command.brigadier.argument.CustomArgumentType; import org.jspecify.annotations.NullMarked; @NullMarked public class BasicImplementation implements CustomArgumentType { @Override public String parse(StringReader reader) { return reader.readUnquotedString(); } @Override public ArgumentType getNativeType() { return StringArgumentType.word(); } } ``` ### Usage Notes The example uses `reader.readUnquotedString()` to parse input. This approach allows for manual string reader operations and can mimic existing argument types like `StringArgumentType.word()`. ``` -------------------------------- ### RegistryKey Interface Example Source: https://docs.papermc.io/paper/dev/command-api/arguments/registry This code shows the definition of a RegistryKey for items, demonstrating how generic types specify the return type. ```java public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { // ... RegistryKey ITEM = RegistryKeyImpl.create("item"); // ... } ``` -------------------------------- ### Chaining 'then' for 'eat' subcommand Source: https://docs.papermc.io/paper/dev/command-api/basics/command-tree Example of chaining '.then()' calls to define the 'eat' subcommand with its own branches. ```java eat .then(Commands.literal("ice-cream")) .then(Commands.literal("main-dish")); ``` -------------------------------- ### Example Deprecated Method Source: https://docs.papermc.io/paper/dev/roadmap This is an example of a method marked with the @Deprecated annotation. Avoid using deprecated APIs as they may become unstable or be removed in future versions. ```java @Deprecated public void exampleMethod(); // Example deprecated method ``` -------------------------------- ### Vulnerable Login Method Example Source: https://docs.papermc.io/paper/dev/using-databases Demonstrates insecure string concatenation that leads to SQL injection vulnerabilities. ```java public void login(String username, String password) { String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'"; // Execute SQL } ``` -------------------------------- ### Example Main Plugin Class Source: https://docs.papermc.io/paper/dev/project-setup This is a basic implementation of a main plugin class that extends JavaPlugin and implements Listener. It registers itself for events and sends a message to players when they join. ```java package io.papermc.testplugin; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.plugin.java.JavaPlugin; public class ExamplePlugin extends JavaPlugin implements Listener { @Override public void onEnable() { Bukkit.getPluginManager().registerEvents(this, this); } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { event.getPlayer().sendMessage(Component.text("Hello, " + event.getPlayer().getName() + "!")); } } ``` -------------------------------- ### Example of a Player Argument with Custom Suggestions and Execution Logic Source: https://docs.papermc.io/paper/dev/command-api/basics/custom-arguments This snippet shows how to define a player argument with custom suggestions for online operators and includes execution logic to verify if the selected player is an operator. It highlights the verbosity of implementing such logic directly within the command tree. ```java Commands.argument("player", ArgumentTypes.player()) .suggests((ctx, builder) -> { Bukkit.getOnlinePlayers().stream() .filter(ServerOperator::isOp) .map(Player::getName) .filter(name -> name.toLowerCase(Locale.ROOT).startsWith(builder.getRemainingLowerCase())) .forEach(builder::suggest); return builder.buildFuture(); }) .executes(ctx -> { final Player player = ctx.getArgument("player", PlayerSelectorArgumentResolver.class).resolve(ctx.getSource()).getFirst(); if (!player.isOp()) { final Message message = MessageComponentSerializer.message().serialize(text(player.getName() + " is not a server operator!")); throw new SimpleCommandExceptionType(message).create(); } ctx.getSource().getSender().sendRichMessage("Player is an operator!", Placeholder.component("player", player.displayName()) ); return Command.SINGLE_SUCCESS; }) ``` -------------------------------- ### Spawn Note Particle with Specific Color Fraction Source: https://docs.papermc.io/paper/dev/particles Spawn note particles with a specific color by setting offsetX to a fraction of 24. This example uses 2.0/24.0 to achieve a specific vanilla note color. ```java Particle.NOTE.builder() .location(someLocation) .offset(2.0f/24.0f, 0, 0) .count(0) .receivers(32, true) .spawn(); ``` ```java someWorld.spawnParticle(Particle.NOTE, someLocation, 0, 2.0f/24.0f, 0, 0); ``` -------------------------------- ### Implement player argument Source: https://docs.papermc.io/paper/dev/command-api/arguments/entity-player Retrieves a target player and modifies their velocity as an example of player-specific argument handling. ```java public static LiteralCommandNode playerArgument() { return Commands.literal("player") .then(Commands.argument("target", ArgumentTypes.player()) .executes(ctx -> { final PlayerSelectorArgumentResolver targetResolver = ctx.getArgument("target", PlayerSelectorArgumentResolver.class); final Player target = targetResolver.resolve(ctx.getSource()).getFirst(); target.setVelocity(new Vector(0, 100, 0)); target.sendRichMessage("Yeeeeeeeeeet"); ctx.getSource().getSender().sendRichMessage("Yeeted !", Placeholder.component("target", target.name()) ); return Command.SINGLE_SUCCESS; })) .build(); } ``` -------------------------------- ### Spawn Dust Transition Particles Source: https://docs.papermc.io/paper/dev/particles Use Particle.DUST_COLOR_TRANSITION for particles that change color. A Particle.DustTransition is used to specify the start and end colors. ```java Particle.DUST_COLOR_TRANSITION.builder() .location(someLocation) .offset(0.5, 0, 0) .count(3) .colorTransition(Color.RED, Color.BLUE) .receivers(32, true) .spawn(); ``` ```java someWorld.spawnParticle( Particle.DUST_COLOR_TRANSITION, someLocation, 3, 0.5, 0, 0, new Particle.DustTransition(Color.RED, Color.BLUE, 1.0f) ); ``` -------------------------------- ### Register Configured Lifecycle Event Handler Source: https://docs.papermc.io/paper/dev/lifecycle Register a configured event handler with the lifecycle manager. This example shows chaining configuration and registration. ```java @Override public void onEnable() { final LifecycleEventManager lifecycleManager = this.getLifecycleManager(); PrioritizedLifecycleEventHandlerConfiguration config = LifecycleEvents.SOME_EVENT.newHandler((event) -> { // Handler for the event }).priority(10); lifecycleManager.registerEventHandler(config); } ``` -------------------------------- ### Asynchronous Suggestion Building Source: https://docs.papermc.io/paper/dev/command-api/basics/argument-suggestions An example of providing suggestions asynchronously using CompletableFuture.supplyAsync. This is necessary when using Paper API calls that must be executed asynchronously. ```java // Here, most Paper API is not usable Commands.argument("name", StringArgumentType.word()) .suggests((ctx, builder) -> CompletableFuture.supplyAsync(() -> { builder.suggest("first"); builder.suggest("second"); return builder.build(); })); ``` -------------------------------- ### Accessing Mappings via Static Methods (Groovy DSL) Source: https://docs.papermc.io/paper/dev/userdev When using Gradle with the Groovy DSL, access mapping configuration fields via static methods. This example shows how to access the Mojang production configuration. ```gradle paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.getMOJANG_PRODUCTION() ``` -------------------------------- ### Constructing Components Source: https://docs.papermc.io/paper/dev/component-api/introduction Demonstrates sub-optimal object-based construction versus optimal builder-based construction for Adventure components. ```java // This is a sub-optimal construction of the // component as each change creates a new component final Component component = Component.text("Hello") .color(TextColor.color(0x13f832)) .append(Component.text(" world!", NamedTextColor.GREEN)); /* This is an optimal use of the builder to create the same component. Also note that Adventure Components are designed for use with static method imports to make code less verbose */ final Component component = text() .content("Hello").color(color(0x13f832)) .append(text(" world!", GREEN)) .build(); ``` -------------------------------- ### Constructing and Using ForwardingAudiences Source: https://docs.papermc.io/paper/dev/component-api/audiences Demonstrates how to treat the server as a forwarding audience and how to create custom audiences from collections. ```java // Server is a ForwardingAudience which includes all online players and the console ForwardingAudience audience = Bukkit.getServer(); // To construct an audience from a collection of players, use: Audience audience = Audience.audience(Audience...); // If you pass in a single Audience, it will be returned as-is. If you pass in a collection of Audiences, they will be // wrapped in a ForwardingAudience. ``` -------------------------------- ### Define load timing Source: https://docs.papermc.io/paper/dev/plugin-yml Sets when the plugin should load during server startup. ```yaml load: STARTUP ``` -------------------------------- ### SQL Injection Payload Source: https://docs.papermc.io/paper/dev/using-databases Example of a malicious input string used to bypass authentication. ```text ' OR 1=1; -- ``` -------------------------------- ### Create and Show a Simple Notice Dialog Source: https://docs.papermc.io/paper/dev/dialogs Constructs a basic notice-type dialog with a title and displays it to a player. Requires importing Dialog, DialogBase, Component, DialogType, and Player. ```java Dialog dialog = Dialog.create(builder -> builder.empty() .base(DialogBase.builder(Component.text("Title")).build()) .type(DialogType.notice()) ); player.showDialog(dialog); ``` -------------------------------- ### Get LifecycleEventManager from BootstrapContext Source: https://docs.papermc.io/paper/dev/lifecycle Obtain the LifecycleEventManager instance tied to a BootstrapContext when using a bootstrapper. ```java @Override public void bootstrap(BootstrapContext context) { final LifecycleEventManager lifecycleManager = context.getLifecycleManager(); } ``` -------------------------------- ### Implement PluginBootstrap Source: https://docs.papermc.io/paper/dev/getting-started/paper-plugins Provides a custom bootstrapper implementation to initialize the plugin and pass parameters to the constructor. ```java public class TestPluginBootstrap implements PluginBootstrap { @Override public void bootstrap(BootstrapContext context) { } @Override public JavaPlugin createPlugin(PluginProviderContext context) { return new TestPlugin("My custom parameter"); } } ``` -------------------------------- ### Component JSON Format Source: https://docs.papermc.io/paper/dev/component-api/introduction Example of the standard JSON structure used for serializing and deserializing components. ```json { "text": "This is the parent component; its style is applied to all children.\n", "color": "#438df2", "bold": true, "extra": [ { "text": "This is this first child, which is rendered after the parent", "underlined": true, // This overrides the parent's "bold" value just for this component "bold": false }, { // This is a keybind component which will display the client's keybind for that action "keybind": "key.inventory" } ] } ``` -------------------------------- ### Configure Java Launcher for Paperweight Source: https://docs.papermc.io/paper/dev/userdev If you encounter issues with paperweightUserdevSetup, configure the javaLauncher property in your build.gradle.kts to specify a compatible Java version for the dev bundle. ```gradle paperweight { javaLauncher = javaToolchains.launcherFor { // Example scenario: // Paper 1.17.1 was originally built with JDK 16 and the bundle // has not been updated to work with 21+ (but we want to compile with a 25 toolchain) languageVersion = JavaLanguageVersion.of(17) } } ``` -------------------------------- ### Get LifecycleEventManager from Plugin Source: https://docs.papermc.io/paper/dev/lifecycle Obtain the LifecycleEventManager instance tied to a Plugin in your plugin's main class. ```java @Override public void onEnable() { final LifecycleEventManager lifecycleManager = this.getLifecycleManager(); } ``` -------------------------------- ### Create Block State Argument Source: https://docs.papermc.io/paper/dev/command-api/arguments/paper Use this to get a block type and its associated data. It requires the ArgumentTypes.blockState() method. ```java public static LiteralCommandNode blockStateArgument() { return Commands.literal("blockstateargument") .then(Commands.argument("arg", ArgumentTypes.blockState()) .executes(ctx -> { final BlockState blockState = ctx.getArgument("arg", BlockState.class); ctx.getSource().getSender().sendPlainMessage("You specified a " + blockState.getType() + "!"); return Command.SINGLE_SUCCESS; })) .build(); } ``` -------------------------------- ### Configure paper-skip-libraries Source: https://docs.papermc.io/paper/dev/plugin-yml Set to true to delegate library loading to a Paper plugin loader. ```yaml paper-skip-libraries: false ``` -------------------------------- ### Creating subcommands with chained 'then' calls Source: https://docs.papermc.io/paper/dev/command-api/basics/command-tree Define subcommands like 'eat' and 'killall' with their respective branches using chained '.then()' calls, and then attach them to a root command. ```java LiteralArgumentBuilder eat = Commands.literal("eat") .then(Commands.literal("ice-cream")) .then(Commands.literal("main-dish")); LiteralArgumentBuilder killall = Commands.literal("killall") .then(Commands.literal("entities")) .then(Commands.literal("players")) .then(Commands.literal("zombies")); LiteralArgumentBuilder advancedCommandRoot = Commands.literal("advanced"); advancedCommandRoot.then(eat); advancedCommandRoot.then(killall); ``` -------------------------------- ### Shaped Recipe Crafting Grid Pattern Source: https://docs.papermc.io/paper/dev/recipes Visual representation of the pattern used in a shaped recipe. This example shows a 3x3 grid. ```plaintext AAA ABA AAA ``` -------------------------------- ### Configure Mojang Mappings in Build Script Source: https://docs.papermc.io/paper/dev/userdev Use this configuration to set your main output to use Mojang mappings. Ensure `reobfJar` dependencies are removed. ```gradle paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION ``` -------------------------------- ### Get Global Region Scheduler Source: https://docs.papermc.io/paper/dev/folia-support Fetch the global scheduler for tasks that do not belong to any particular region. This scheduler operates on the global region. ```java GlobalRegionScheduler globalScheduler = server.getGlobalRegionScheduler(); ``` -------------------------------- ### Get HandlerList for an Event Source: https://docs.papermc.io/paper/dev/handler-lists Retrieve the HandlerList associated with a specific event. This can be done either from an event instance or directly from the event class. ```java public class ExampleListener implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { HandlerList handlerList = event.getHandlerList(); // ... } // Or: public ExampleListener() { // Access the handler list through the static getter HandlerList handlerList = PlayerJoinEvent.getHandlerList(); // ... } } ``` -------------------------------- ### Using MiniMessage Source: https://docs.papermc.io/paper/dev/component-api/introduction Shows how to deserialize MiniMessage strings into components and how to implement a helper method for cleaner syntax. ```java final Component component = MiniMessage.miniMessage().deserialize( "<#438df2>This is the parent component; its style is " + "applied to all children.\nThis is the first child, " + "which is rendered after the parent" ); // if the syntax above is too verbose for you, create a helper method! public final class Components { public static Component mm(String miniMessageString) { // mm, short for MiniMessage return MiniMessage.miniMessage().deserialize(miniMessageString); } } // ... import static io.papermc.docs.util.Components.mm; // replace with your own package final Component component = mm("Hello World!"); ``` -------------------------------- ### Configure Plugin Management Repositories Source: https://docs.papermc.io/paper/dev/userdev Add Paper's Maven repository to your pluginManagement repositories in build.gradle.kts. This is necessary for resolving SNAPSHOT versions of paperweight-userdev. ```gradle pluginManagement { repositories { gradlePluginPortal() maven("https://repo.papermc.io/repository/maven-public/") } } ``` -------------------------------- ### Create a Custom Mob Goal Source: https://docs.papermc.io/paper/dev/mob-goals Implements the Goal interface to define custom mob behavior. This example shows a camel following a player. ```Java @NullMarked public class CamelFollowPlayerGoal implements Goal { // This is the key for the goal. It is used to identify the goal and is // used to determine if two goals are the same. public static final GoalKey KEY = GoalKey.of( // The entity class this goal is targeting. Camel.class, // The key used for identification. Should use your plugin's namespace. new NamespacedKey("testplugin", "camel_follow_player") ); private final Player player; // The player to follow. private final Camel camel; // The camel that is following. public CamelFollowPlayerGoal(Player player, Camel camel) { this.player = player; this.camel = camel; } @Override public boolean shouldActivate() { // Whether the goal should start. In this case, we want the goal to always // start so we return true. You could also return false if a specific // condition needs to be met. return true; } @Override public void start() { // Called when the goal starts. player.sendMessage(text("I am following you!")); } @Override public void tick() { // Called every tick while the goal is running. Here, we make the camel // move towards the player using the Pathfinder API. // The 5.0 is the speed of the camel. camel.getPathfinder().moveTo(player, 5.0); } @Override public void stop() { // Called when the goal stops. player.sendMessage(text("I stopped following you!")); } @Override public GoalKey getKey() { return KEY; } @Override public EnumSet getTypes() { // Returns the types of this goal. Since we are changing the // camel's look direction and move it, we return MOVE and LOOK. // You may return as many types as you need. return EnumSet.of(GoalType.MOVE, GoalType.LOOK); } } ``` -------------------------------- ### Define main class Source: https://docs.papermc.io/paper/dev/plugin-yml Specifies the entry point class that extends JavaPlugin. ```yaml main: io.papermc.testplugin.ExamplePlugin ``` -------------------------------- ### Connect to a Database with HikariCP Source: https://docs.papermc.io/paper/dev/using-databases Initializes a HikariDataSource to manage database connections. Ensure the HikariCP dependency is included in your project. ```java public class DatabaseManager { public void connect() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/mydatabase"); // Address of your running MySQL database config.setUsername("username"); // Username config.setPassword("password"); // Password config.setMaximumPoolSize(10); // Pool size defaults to 10 config.addDataSourceProperty("", ""); // MISC settings to add HikariDataSource dataSource = new HikariDataSource(config); try (Connection connection = dataSource.getConnection()) { // Use a try-with-resources here to autoclose the connection. PreparedStatement sql = connection.prepareStatement("SQL"); // Execute statement } catch (Exception e) { // Handle any exceptions that arise from getting / handing the exception. } } } ``` -------------------------------- ### Remove Discovered Datapacks Source: https://docs.papermc.io/paper/dev/lifecycle/datapacks Prevent specific datapacks from being loaded by calling `removeDiscoveredPack` with the datapack's name. This example removes experimental datapacks. ```java // The names of the datapacks we want to remove. final Set 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()) ); ``` -------------------------------- ### Create a custom sword Source: https://docs.papermc.io/paper/dev/data-component-api Demonstrates applying multiple data components like lore, enchantments, and rarity to an item. ```java ItemStack sword = ItemStack.of(Material.DIAMOND_SWORD); sword.setData(DataComponentTypes.LORE, ItemLore.lore().addLine(Component.text("Cool sword!")).build()); sword.setData(DataComponentTypes.ENCHANTMENTS, ItemEnchantments.itemEnchantments().add(Enchantment.SHARPNESS, 10).build()); sword.setData(DataComponentTypes.RARITY, ItemRarity.RARE); sword.unsetData(DataComponentTypes.TOOL); // Remove the tool component sword.setData(DataComponentTypes.MAX_DAMAGE, 10); sword.setData(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, true); // Make it glow! ``` -------------------------------- ### Scale BlockDisplay Entity Source: https://docs.papermc.io/paper/dev/display-entities Spawn a BlockDisplay entity and apply scaling transformations. This example scales a grass block by a factor of 2 on all axes. ```java world.spawn(location, BlockDisplay.class, entity -> { entity.setBlock(Material.GRASS_BLOCK.createBlockData()); entity.setTransformation( new Transformation( new Vector3f(), // no translation new AxisAngle4f(), // no left rotation new Vector3f(2, 2, 2), // scale up by a factor of 2 on all axes new AxisAngle4f() // no right rotation ) ); // or set a raw transformation matrix from JOML // entity.setTransformationMatrix( // new Matrix4f() // .scale(2) // scale up by a factor of 2 on all axes // ); }); ``` -------------------------------- ### Register a Listener in onEnable Source: https://docs.papermc.io/paper/dev/event-listeners Register your listener instance with the PluginManager in your plugin's `onEnable()` method. This ensures the listener is active when the server starts. ```java public class ExamplePlugin extends JavaPlugin { @Override public void onEnable() { getServer().getPluginManager().registerEvents(new ExampleListener(), this); } } ``` -------------------------------- ### Flyspeed Command Implementation Source: https://docs.papermc.io/paper/dev/command-api/basics/executors This snippet demonstrates how to implement a `/flyspeed` command using `ArgumentBuilder`. It includes retrieving arguments, checking sender and executor types, and setting the player's fly speed. Note the use of `CommandSender` and `Entity` for interaction. ```java Commands.literal("flyspeed") .then(Commands.argument("speed", FloatArgumentType.floatArg(0, 1.0f)) .executes(ctx -> { float speed = FloatArgumentType.getFloat(ctx, "speed"); // Retrieve the speed argument CommandSender sender = ctx.getSource().getSender(); // Retrieve the command sender Entity executor = ctx.getSource().getExecutor(); // Retrieve the command executor, which may or may not be the same as the sender // Check whether the executor is a player, as you can only set a player's flight speed if (!(executor instanceof Player player)) { // If a non-player tried to set their own flight speed sender.sendPlainMessage("Only players can fly!"); return Command.SINGLE_SUCCESS; } // Set the player's speed player.setFlySpeed(speed); if (sender == executor) { // If the player executed the command themselves player.sendPlainMessage("Successfully set your flight speed to " + speed); return Command.SINGLE_SUCCESS; } // If the speed was set by a different sender (Like using /execute) sender.sendRichMessage("Successfully set 's flight speed to " + speed, Placeholder.component("playername", player.name())); player.sendPlainMessage("Your flight speed has been set to " + speed); return Command.SINGLE_SUCCESS; }) ); ``` -------------------------------- ### Register Basic Command with Lambda Source: https://docs.papermc.io/paper/dev/command-api/misc/basic-command Basic commands can be registered using lambda expressions for concise implementation, though this is not recommended for readability. The lambda directly provides the command execution logic. ```java @Override public void onEnable() { registerCommand( "quickcmd", (source, args) -> source.getSender().sendRichMessage("Hello!") ); } ``` -------------------------------- ### Define Deepest Branches for Advanced Command Source: https://docs.papermc.io/paper/dev/command-api/basics/command-tree Start by defining the literal arguments for the deepest subcommands that have no further children. This forms the base of your command tree. ```java LiteralArgumentBuilder entities = Commands.literal("entities"); LiteralArgumentBuilder players = Commands.literal("players"); LiteralArgumentBuilder zombies = Commands.literal("zombies"); LiteralArgumentBuilder iceCream = Commands.literal("ice-cream"); LiteralArgumentBuilder mainDish = Commands.literal("main-dish"); ``` -------------------------------- ### Initialize SQLite Database Connection Source: https://docs.papermc.io/paper/dev/using-databases Invoke Class.forName() on the driver to initialize it, then establish a connection to the SQLite database file. This is for file-based databases. ```java public class DatabaseManager { public void connect() { Class.forName("org.sqlite.JDBC"); Connection connection = DriverManager.getConnection("jdbc:sqlite:plugins/TestPlugin/database.db"); } } ``` -------------------------------- ### Bukkit Command Implementation Source: https://docs.papermc.io/paper/dev/command-api/misc/comparison-bukkit-brigadier Extends BukkitCommand to handle command execution and tab completion. Requires manual validation of arguments and player existence. ```java package your.package.name; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.entity.Player; import org.jspecify.annotations.NullMarked; import java.util.List; @NullMarked public class BukkitPartyCommand extends BukkitCommand { public BukkitPartyCommand(String name, String description, String usageMessage, List aliases) { super(name, description, usageMessage, aliases); } @Override public boolean execute(CommandSender sender, String commandLabel, String[] args) { if (args.length == 0) { sender.sendPlainMessage("Please provide a player!"); return false; } final Player targetPlayer = Bukkit.getPlayer(args[0]); if (targetPlayer == null) { sender.sendPlainMessage("Please provide a valid player!"); return false; } targetPlayer.sendPlainMessage(sender.getName() + " started partying with you!"); sender.sendPlainMessage("You are now partying with " + targetPlayer.getName() + "!"); return true; } @Override public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { if (args.length == 1) { return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(); } return List.of(); } } ``` -------------------------------- ### Get Async Scheduler Source: https://docs.papermc.io/paper/dev/folia-support Retrieve the async scheduler for running tasks independently of the server's tick process. This is useful for non-time-critical background operations. ```java AsyncScheduler asyncScheduler = server.getAsyncScheduler(); ``` -------------------------------- ### Retrieve Executor or Sender Name Source: https://docs.papermc.io/paper/dev/command-api/misc/basic-command Get the name of the command executor if available, otherwise use the sender's name. This ensures compatibility with '/execute as'. ```java final Component name = source.getExecutor() != null ? source.getExecutor().name() : source.getSender().name(); ``` -------------------------------- ### Register translation source Source: https://docs.papermc.io/paper/dev/component-api/i18n Create a TranslationStore, load a ResourceBundle, and register it with the GlobalTranslator. ```java TranslationStore.StringBased store = TranslationStore.messageFormat(Key.key("namespace:value")); ResourceBundle bundle = ResourceBundle.getBundle("your.plugin.Bundle", Locale.US, UTF8ResourceBundleControl.get()); store.registerAll(Locale.US, bundle, true); GlobalTranslator.translator().addSource(store); ``` -------------------------------- ### Rotate and Scale BlockDisplay Entity Source: https://docs.papermc.io/paper/dev/display-entities Spawn a BlockDisplay entity and apply combined rotation and scaling transformations. This example tips a grass block on its corner and scales it. ```java world.spawn(location, BlockDisplay.class, entity -> { entity.setBlock(Material.GRASS_BLOCK.createBlockData()); entity.setTransformation( new Transformation( new Vector3f(), // no translation new AxisAngle4f((float) -Math.toRadians(45), 1, 0, 0), // rotate -45 degrees on the X axis new Vector3f(2, 2, 2), // scale up by a factor of 2 on all axes new AxisAngle4f((float) Math.toRadians(45), 0, 0, 1) // rotate +45 degrees on the Z axis ) ); // or set a raw transformation matrix from JOML // entity.setTransformationMatrix( // new Matrix4f() // .scale(2) // scale up by a factor of 2 on all axes // .rotateXYZ( // (float) Math.toRadians(360 - 45), // rotate -45 degrees on the X axis // 0, // (float) Math.toRadians(45) // rotate +45 degrees on the Z axis // ) // ); }); ``` -------------------------------- ### Create a Listener Class Source: https://docs.papermc.io/paper/dev/event-listeners To listen for events, create a class that implements the `Listener` interface. Name the class descriptively. ```java public class ExampleListener implements Listener { // ... } ``` -------------------------------- ### Handling empty arguments for suggestions Source: https://docs.papermc.io/paper/dev/command-api/misc/basic-command Returns all player names when no arguments are provided to the command. ```java if (args.length == 0) { return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(); } ``` -------------------------------- ### Synchronous Suggestion Building Source: https://docs.papermc.io/paper/dev/command-api/basics/argument-suggestions An example of providing suggestions synchronously within the lambda. This approach is suitable when no Paper API calls that require an async context are needed. ```java Commands.argument("name", StringArgumentType.word()) .suggests((ctx, builder) -> { builder.suggest("first"); builder.suggest("second"); return builder.buildFuture(); }); ``` -------------------------------- ### Move Entity to Player Location Source: https://docs.papermc.io/paper/dev/entity-pathfinder Get the pathfinder for a mob and set its destination to a player's location. The `moveTo` method returns a boolean indicating success. ```java Cow cow = ...; Player player = ...; Pathfinder pathfinder = cow.getPathfinder(); // moveTo returns a boolean indicating whether the path was set successfully boolean success = pathfinder.moveTo(player.getLocation()); ``` -------------------------------- ### Use translatable components Source: https://docs.papermc.io/paper/dev/component-api/i18n Create a component using a translation key and provide arguments for placeholders. ```java Component.translatable("some.translation.key", Component.text("The Argument")) ``` -------------------------------- ### Retrieve Enchantment by TypedKey Source: https://docs.papermc.io/paper/dev/registries Fetches the enchantment registry and retrieves the 'minecraft:sharpness' enchantment using a `TypedKey`. Ensure the registry contains the value, or use `get`. ```java final Registry enchantmentRegistry = RegistryAccess .registryAccess() .getRegistry(RegistryKey.ENCHANTMENT); final Enchantment enchantment = enchantmentRegistry.getOrThrow(TypedKey.create( RegistryKey.ENCHANTMENT, Key.key("minecraft:sharpness")) ); ``` -------------------------------- ### Require Player to Have Diamond Sword Source: https://docs.papermc.io/paper/dev/command-api/basics/requirements This example checks if the executing player has a diamond sword in their inventory. Note that this can lead to client-side desync if not handled properly with command updates. ```java Commands.literal("givesword") .requires(sender -> sender.getExecutor() instanceof Player player && !player.getInventory().contains(Material.DIAMOND_SWORD)) .executes(ctx -> { if (ctx.getSource().getExecutor() instanceof Player player) { player.getInventory().addItem(ItemType.DIAMOND_SWORD.createItemStack()); } return Command.SINGLE_SUCCESS; }); ``` -------------------------------- ### Complete BroadcastCommand implementation Source: https://docs.papermc.io/paper/dev/command-api/misc/basic-command The full class implementation including command execution logic, permissions, and filtered player name suggestions. ```java package your.package.name; import io.papermc.paper.command.brigadier.BasicCommand; import io.papermc.paper.command.brigadier.CommandSourceStack; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import java.util.Collection; @NullMarked public class BroadcastCommand implements BasicCommand { @Override public void execute(CommandSourceStack source, String[] args) { final Component name = source.getExecutor() != null ? source.getExecutor().name() : source.getSender().name(); if (args.length == 0) { source.getSender().sendRichMessage("You cannot send an empty broadcast!"); return; } final String message = String.join(" ", args); final Component broadcastMessage = MiniMessage.miniMessage().deserialize( "BROADCAST ยป ", Placeholder.component("name", name), Placeholder.unparsed("message", message) ); Bukkit.broadcast(broadcastMessage); } @Override public @Nullable String permission() { return "example.broadcast.use"; } @Override public Collection suggest(CommandSourceStack source, String[] args) { if (args.length == 0) { return Bukkit.getOnlinePlayers().stream().map(Player::getName).toList(); } return Bukkit.getOnlinePlayers().stream() .map(Player::getName) .filter(name -> name.toLowerCase().startsWith(args[args.length - 1].toLowerCase())) .toList(); } } ``` -------------------------------- ### Get Entity Scheduler Source: https://docs.papermc.io/paper/dev/folia-support Obtain the entity scheduler for executing tasks directly on an entity. These tasks follow the entity across regions, making them preferable to region schedulers for entity-specific operations. ```java EntityScheduler scheduler = entity.getScheduler(); ``` -------------------------------- ### Suggest Item Amounts in Command Source: https://docs.papermc.io/paper/dev/command-api/basics/argument-suggestions Use `builder.suggest()` to offer common item amounts like 1, 16, 32, and 64 when a player is typing the amount argument in a command. This requires the `CommandSourceStack` and `SuggestionsBuilder` from the Paper API. ```java @NullMarked public class SuggestionsTest { public static LiteralCommandNode constructGiveItemCommand() { // Create new command: /giveitem return Commands.literal("giveitem") // Require a player to execute the command .requires(ctx -> ctx.getExecutor() instanceof Player) // Declare a new ItemStack argument .then(Commands.argument("item", ArgumentTypes.itemStack()) // Declare a new integer argument with the bounds of 1 to 99 .then(Commands.argument("amount", IntegerArgumentType.integer(1, 99)) // Here, we use method references, since otherwise, our command definition would grow too big .suggests(SuggestionsTest::getAmountSuggestions) .executes(SuggestionsTest::executeCommandLogic) ) ) .build(); } private static CompletableFuture getAmountSuggestions(final CommandContext ctx, final SuggestionsBuilder builder) { // Suggest 1, 16, 32, and 64 to the user when they reach the 'amount' argument builder.suggest(1); builder.suggest(16); builder.suggest(32); builder.suggest(64); return builder.buildFuture(); } private static int executeCommandLogic(final CommandContext ctx) { // We know that the executor will be a player, so we can just silently return if (!(ctx.getSource().getExecutor() instanceof Player player)) { return Command.SINGLE_SUCCESS; } // If the player has no empty slot, we tell the player that they have no free inventory space final int firstEmptySlot = player.getInventory().firstEmpty(); if (firstEmptySlot == -1) { player.sendRichMessage("You do not have enough space in your inventory!"); return Command.SINGLE_SUCCESS; } // Retrieve our argument values final ItemStack item = ctx.getArgument("item", ItemStack.class); final int amount = IntegerArgumentType.getInteger(ctx, "amount"); // Set the item's amount and give it to the player item.setAmount(amount); player.getInventory().setItem(firstEmptySlot, item); // Send a confirmation message player.sendRichMessage("You have been given x !", Placeholder.component("amount", Component.text(amount)), Placeholder.component("item", Component.translatable(item).hoverEvent(item)) ); return Command.SINGLE_SUCCESS; } } ``` -------------------------------- ### Define external libraries Source: https://docs.papermc.io/paper/dev/plugin-yml Lists dependencies to be downloaded from Maven Central. ```yaml libraries: - com.google.guava:guava:30.1.1-jre - com.google.code.gson:gson:2.8.6 ``` -------------------------------- ### Custom Chat Message Formatting Source: https://docs.papermc.io/paper/dev/chat-events Return a new Component from the render method to define the custom format of the chat message. This example appends the message to the source's display name with a colon. ```java public class ChatListener implements Listener, ChatRenderer { // Listener logic @Override public Component render(Player source, Component sourceDisplayName, Component message, Audience viewer) { return sourceDisplayName .append(Component.text(": ")) .append(message); } } ``` -------------------------------- ### Combining root and subcommands with chained 'then' Source: https://docs.papermc.io/paper/dev/command-api/basics/command-tree Build a complex command structure by chaining '.then()' calls for both the root command and its subcommands, creating a deeply nested command tree. ```java LiteralArgumentBuilder advancedCommandRoot = Commands.literal("advanced") .then(Commands.literal("eat") .then(Commands.literal("ice-cream")) .then(Commands.literal("main-dish")) ) .then(Commands.literal("killall") .then(Commands.literal("entities")) .then(Commands.literal("players")) .then(Commands.literal("zombies")) ); ``` -------------------------------- ### Configure plugin dependencies Source: https://docs.papermc.io/paper/dev/plugin-yml Settings for managing plugin load order and functionality requirements. ```yaml depend: [Vault, WorldEdit] ``` ```yaml softdepend: [Vault, WorldEdit] ``` ```yaml loadbefore: [Vault, FactionsUUID] ``` ```yaml provides: [SomeOtherPlugin] ``` -------------------------------- ### Example Stacktrace Analysis Source: https://docs.papermc.io/paper/dev/reading-stacktraces This stacktrace shows a NullPointerException during plugin enablement. It details the error, the specific line of code causing it (TestPlugin.java:23), and the sequence of calls leading to the error, allowing developers to pinpoint and fix the issue. ```java [15:20:42 ERROR]: Could not pass event PluginEnableEvent to TestPlugin v1.0 java.lang.NullPointerException: Cannot invoke "Object.toString()" because "player" is null at io.papermc.testplugin.TestPlugin.onPluginEnable(TestPlugin.java:23) ~[TestPlugin-1.0-SNAPSHOT.jar:?] at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor1.execute(Unknown Source) ~[?:?] at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:77) ~[paper-api-1.20.2-R0.1-SNAPSHOT.jar:?] at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:81) ~[paper-api-1.20.2-R0.1-SNAPSHOT.jar:git-Paper-49] at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[paper-api-1.20.2-R0.1-SNAPSHOT.jar:?] at io.papermc.paper.plugin.manager.PaperEventManager.callEvent(PaperEventManager.java:54) ~[paper-1.20.2.jar:git-Paper-49] at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.callEvent(PaperPluginManagerImpl.java:126) ~[paper-1.20.2.jar:git-Paper-49] at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:615) ~[paper-api-1.20.2-R0.1-SNAPSHOT.jar:?] at io.papermc.paper.plugin.manager.PaperPluginInstanceManager.enablePlugin(PaperPluginInstanceManager.java:200) ~[paper-1.20.2.jar:git-Paper-49] at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.enablePlugin(PaperPluginManagerImpl.java:104) ~[paper-1.20.2.jar:git-Paper-49] at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:507) ~[paper-api-1.20.2-R0.1-SNAPSHOT.jar:?] at org.bukkit.craftbukkit.v1_20_R2.CraftServer.enablePlugin(CraftServer.java:636) ~[paper-1.20.2.jar:git-Paper-49] at org.bukkit.craftbukkit.v1_20_R2.CraftServer.enablePlugins(CraftServer.java:547) ~[paper-1.20.2.jar:git-Paper-49] at net.minecraft.server.MinecraftServer.loadWorld0(MinecraftServer.java:636) ~[paper-1.20.2.jar:git-Paper-49] at net.minecraft.server.MinecraftServer.loadLevel(MinecraftServer.java:435) ~[paper-1.20.2.jar:git-Paper-49] at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:308) ~[paper-1.20.2.jar:git-Paper-49] at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1101) ~[paper-1.20.2.jar:git-Paper-49] at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:318) ~[paper-1.20.2.jar:git-Paper-49] at java.lang.Thread.run(Thread.java:833) ~[?:?] ``` -------------------------------- ### Create a Basic Custom Event Source: https://docs.papermc.io/paper/dev/custom-events Define a custom event class extending `Event` and include a static `getHandlerList()` method returning a `HandlerList`. This is the fundamental structure for any custom event. ```java public class PaperIsCoolEvent extends Event { private static final HandlerList HANDLER_LIST = new HandlerList(); public static HandlerList getHandlerList() { return HANDLER_LIST; } @Override public HandlerList getHandlers() { return HANDLER_LIST; } } ```