Paper Minecraft Server

repository·main·Indexed 10 days ago

https://github.com/papermc/paper

A high-performance Minecraft server implementation designed to fix gameplay and mechanics inconsistencies found in vanilla Minecraft. It provides a robust API for plugin development, including Brigadier command argument integration, performance profiling via TimingHandler, and block predicate builders. Supports Java 25 and is distributed as a Paperclip jar.

Tokens
37.4K
Snippets
109
Records
156
Agent score
95%

What's inside Paper

  1. Understand the implications of the GNU GPL v3

    main

    The GNU General Public License (GPL) is a copyleft license designed to guarantee the freedom to share and change all versions of a program.

    Key Concepts

    • Copyleft: If you distribute a modified version of a GPL-licensed work, you must pass on the same freedoms to the recipients, including providing access to the source code.
    • No Warranty: The software is provided "as is" without any warranty of any kind. The entire risk regarding quality and performance lies with the user.
    • Patent Protection: The license includes provisions to prevent software patents from being used to render a program non-free.
    • Anti-Circumvention: The license prohibits using technological measures to restrict users' rights to modify or run the software under the GPL.
    • Downstream Licensing: Each time you convey a covered work, the recipient automatically receives a license from the original licensors to run, modify, and propagate that work under the same terms.

    Limitations

    • No Proprietary Incorporation: The GPL does not permit incorporating your program into proprietary programs. If you wish to allow proprietary applications to link with your library, consider using the GNU Lesser General Public License (LGPL) instead.
  2. Add Paper API as a dependency for plugin development

    main

    To develop plugins for Paper, add the Paper API to your build configuration. Use the PaperMC Maven repository and set the dependency scope to provided, as the API is supplied by the server runtime.

    Note: Ensure your project uses the correct Java version (e.g., Java 25) as required by the current Paper version.

    ##### Gradle
    ```kotlin
    repositories {
        maven {
            url = uri("https://repo.papermc.io/repository/maven-public/")
        }
    }
    
    dependencies {
        compileOnly("io.papermc.paper:paper-api:26.2.build.+")
    }
    
    java {
        toolchain.languageVersion.set(JavaLanguageVersion.of(25))
    }
    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>[26.2.build,)</version>
        <scope>provided</scope>
    </dependency>
  3. Apply the GNU GPL v3 to your new programs

    main

    To release a new program under the GNU General Public License (GPL) version 3, you should attach specific notices to your program to clearly state its license and the absence of warranty.

    Source File Notices

    It is recommended to attach the following notice to the start of each source file. Each file should include at least a copyright line and a pointer to the full license text:

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year> <name of author>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

    You should also include contact information for yourself via electronic and paper mail.

    Terminal Interaction Notices

    If your program uses a terminal interface, it should output a short notice upon starting in interactive mode, for example:

    <program>  Copyright (C) <year> <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c'.

    Note: The commands (e.g., show w and show c) should display the appropriate parts of the GPL. For GUI applications, an "about box" is an appropriate equivalent.

  4. Compile Paper from source

    main

    To build a custom Paper jar from the source repository, you must have JDK 25 installed and an active internet connection.

    Follow these steps in your terminal:

    1. Clone the repository.
    2. Run ./gradlew applyPatches to prepare the source.
    3. Run ./gradlew createPaperclipJar to build the executable jar.

    The resulting jar will be located in the paper-server/build/libs directory.

    To see all available Gradle tasks, run ./gradlew tasks.

    ./gradlew applyPatches
    ./gradlew createPaperclipJar
  5. Use ArgumentTypes to create Brigadier command arguments

    main

    The ArgumentTypes class provides a set of static methods to create ArgumentType instances for use in plugin commands. These methods wrap vanilla Minecraft argument types, allowing your plugin commands to benefit from client-side completions, validation, and command signing context.

    When using these methods, the returned ArgumentType<T> will resolve to a specific type T (such as ItemStack, UUID, or World) within your command logic.

    import io.papermc.paper.command.brigadier.argument.ArgumentTypes;
    import com.mojang.brigadier.arguments.ArgumentType;
    import org.bukkit.inventory.ItemStack;
    
    // Example usage in a command definition
    ArgumentType<ItemStack> itemArg = ArgumentTypes.itemStack();
  6. How Folia region threading works

    main

    In Folia, the server is split into multiple regions that tick independently. To interact with the server safely, you must ensure your code is running on the thread that 'owns' the specific location or entity you are accessing.

    Checking Ownership

    Use isOwnedByCurrentRegion(...) to verify if the current thread is the one responsible for ticking a specific:

    • Location or Block.
    • World at a specific Position or Chunk coordinate.
    • Entity (this is the recommended way to check entity ownership).

    Schedulers

    Folia provides specialized schedulers depending on the scope of your task:

    • getRegionScheduler(): For tasks tied to a specific Location. Use this for location-based logic. Do not use this for entities; use Entity#getScheduler() instead, as entity schedulers follow the entity if it teleports.
    • getAsyncScheduler(): For tasks that should run asynchronously from the server tick process.
    • getGlobalRegionScheduler(): For tasks that belong to the global region (e.g., world time, weather, or console commands).

    Note: If you are not writing a plugin specifically for Folia, use the standard getScheduler() instead of these region-specific schedulers.

    // Checking if the current thread owns an entity
    if (server.isOwnedByCurrentRegion(myEntity)) {
        // Safe to perform entity-specific logic
    }
    
    // Scheduling a task in a specific region
    server.getRegionScheduler().execute(plugin, location, () -> {
        // This runs on the thread owning 'location'
    });
  7. How CommandSender relates to Audience and Permissible

    main

    The CommandSender interface extends two key interfaces, allowing it to function within the broader Paper ecosystem:

    1. net.kyori.adventure.audience.Audience: This allows CommandSender to be treated as a recipient for Adventure text components, enabling modern, rich-text communication.
    2. org.bukkit.permissions.Permissible: This allows the sender to be checked for permissions (e.g., via hasPermission(String permission)).
  8. Register Brigadier commands in Paper

    main

    To register custom Brigadier commands, listen for the LifecycleEvents.COMMANDS event via the LifecycleEventManager. Use the Commands registrar provided by the event to register built LiteralCommandNode objects.

    Commands can be registered in two main ways:

    1. Via JavaPlugin: Use the LifecycleEventManager in onEnable().
    2. Via PluginBootstrap: Use the LifecycleEventManager from the BootstrapContext. Commands registered here are available for datapack command function parsing and can override vanilla commands within loaded datapacks.

    When registering, you can provide a help description and a collection of aliases. Note that aliases do not act as Brigadier redirects; they simply copy the command to a different label. The main command/namespaced label will override existing commands, but aliases will not override existing commands (except for namespaced ones).

    class YourPluginClass extends JavaPlugin {
    
        @Override
        public void onEnable() {
            LifecycleEventManager<Plugin> manager = this.getLifecycleManager();
            manager.registerEventHandler(LifecycleEvents.COMMANDS, event -> {
                final Commands commands = event.registrar();
                commands.register(
                    Commands.literal("new-command")
                        .executes(ctx -> {
                            ctx.getSource().getSender().sendPlainMessage("some message");
                            return Command.SINGLE_SUCCESS;
                        })
                        .build(),
                    "some bukkit help description string",
                    List.of("an-alias")
                );
            });
        }
    }
  9. Use the /paper entity list command

    main

    The /paper entity list command allows server administrators to inspect entity counts within a specific world, categorized by whether they are currently ticking or non-ticking. This is useful for identifying entity-related performance issues.

    Usage

    /paper entity list [filter] [world]

    • filter (Optional): A glob-style pattern (using * or ?) to match specific entity types (e.g., minecraft:zombie*). If omitted, it defaults to * (all entities).
    • world (Optional): The NamespacedKey of the world to inspect. If the sender is a player, it defaults to the player's current world. If the sender is not a player and no world is specified, the command will fail.

    Output Behavior

    • If a single entity type matches the filter: The command displays the total ticking and non-ticking counts for that specific entity. It also lists up to 10 chunks with the highest concentrations of that entity. These chunk entries are clickable and will teleport the user to that chunk.
    • If multiple entity types match the filter: The command displays the total ticking and non-ticking counts for the entire group, followed by a breakdown for each matched entity type in the format: Ticking (Non-Ticking): entity_id.
    # Example: List all zombies in the 'world' world
    /paper entity list minecraft:zombie* world
    
    # Example: List all entities in the current world
    /paper entity list *
  10. Define commands in plugin.yml

    main

    When developing a plugin, you can define your commands in the plugin.yml file. The PluginCommandYamlParser reads these definitions to automatically register PluginCommand objects.

    Supported keys for each command in the YAML include:

    • description: A string describing the command.
    • usage: A string showing the correct usage syntax.
    • aliases: A single string or a list of strings representing alternative names for the command. Note that aliases cannot contain the : character.
    • permission: The permission node required to execute the command.
    • permission-message: A legacy-formatted string (supporting section symbols like §) that is sent to players when they lack the required permission.
    commands:
      mycommand:
        description: "A sample command"
        usage: "/mycommand <arg1>"
        aliases: ["cmd1", "cmd2"]
        permission: "myplugin.command.mycommand"
        permission-message: "§cYou do not have permission!"