Your first plugin, step by step
Create a project, write a welcome message, run a real Paper server and see it in game.
On this page you will make a real Paper plugin from nothing: get a project, write a few lines of Java, start a Paper 26.3 test server with one click, join it from Minecraft, and see your plugin greet you in chat. Then you will build the plugin into a jar file you could put on any server.
You do not need to understand every word yet. This page is about getting something working and seeing the whole journey once. Every piece you touch here has its own chapter later, and the last section maps each piece to the page that explains it.
What you will build
Your first plugin does two small things. When the server starts, it writes a line in the server's console, the text window where the server reports what it is doing. When a player joins, it sends that player a welcome message in chat:
This message comes from your very first plugin.
Steve joined the game
The gold and gray lines come from your plugin. The yellow line is Minecraft's normal join message, which the server sends last, after every plugin has had its turn. Small, but it uses the same pieces as every big plugin: a main class the server starts, a listener that reacts to something players do, and a jar file that carries it all.
Step 1: get a project
A plugin starts life as a project: a folder with your code, a few settings files, and a recipe that tells Gradle how to turn your code into a plugin. Gradle is the build tool: it downloads the Paper code your plugin needs and packs everything into a jar. Nobody types those settings files from scratch; you start from a ready-made project. Pick one of these ways:
This works on any computer, and it is the way this page assumes.
- Download the starter project for this page (a small zip file).
- Open your Downloads folder, right-click the zip and choose .
- Windows makes a folder called
first-plugin-startwith a secondfirst-plugin-startfolder inside it. The inner one, the folder that containsbuild.gradle.kts, is your project. Move that inner folder somewhere you keep code, for exampleC:\Users\YourName\IdeaProjects, which IntelliJ uses by default.
The starter already has everything set up: the Gradle files, a main class called FirstPlugin, a plugin.yml, and two ready-made buttons for IntelliJ called Run Paper Server and Build Plugin Jar.
If you have the paper-templates folder on your PC, its new-plugin.cmd script makes a fresh project with your names already filled in. Open PowerShell and type:
cd C:\Users\jacec\IdeaProjects\paper-templates .\new-plugin.cmd -Name FirstPlugin -OpenThe script copies the clean-slate template to C:\Users\jacec\IdeaProjects\first-plugin, renames the package to com.example.firstplugin and the main class to FirstPlugin, and -Open opens it in IntelliJ for you, so you can skip the "File > Open" part of Step 2.
Two small differences from the starter download: the template's plugin.yml says '${version}' instead of '1.0.0' (Gradle fills that in when it builds, so leave it), and the main class may contain a few test lines. You will replace the whole main class in Step 3 anyway.
With the Minecraft Development plugin installed, IntelliJ can create a plugin project for you: , choose Minecraft on the left, then pick Paper as the platform and fill in the names.
It works, but the wizard makes a Maven project (with a pom.xml file) instead of a Gradle one, and it has no Run Paper Server button, so the steps on this page will not match exactly. Use one of the other two ways for now. Anatomy of a plugin project shows what the Maven version looks like.
Step 2: open the project in IntelliJ
Open the folder
Start IntelliJ IDEA and choose (or Open on the welcome screen). Select the project folder itself, the one that contains
build.gradle.kts, and click OK. Do not pick a folder above it or a single file inside it.Open File or ProjectC:\Users\you\IdeaProjects\first-pluginC:\UsersyouDesktopDocumentsIdeaProjectsGfirst-plugin1paper-templatesDownloadsDrag and drop a file into the space above to quickly locate it? OK2 CancelSelect the project folder, not a file inside it Trust the project
IntelliJ asks whether you trust this project, because opening a Gradle project runs its build script. You made it (or downloaded it from this guide), so click Trust Project.
Trust and Open Project 'first-plugin'?IntelliJ IDEA provides features that may automatically execute code contained in this project, for example, while importing it or building it.If you don't trust the source, preview the project in safe mode.Trust projects in C:\Users\you\IdeaProjects1Trust Project2 Preview in Safe Mode Don't OpenChoose Trust Project Wait for Gradle
The first time, Gradle downloads itself and the Paper API, the code library that lets your plugin talk to the server. A progress bar runs at the bottom of the window. This can take a few minutes on the first project and a few seconds after that. Until it finishes, IntelliJ may underline code in red because it does not know the Paper classes yet. That is normal; wait for the bar to disappear.
Find your files
The project tree on the left shows your files. Click the small arrows to open
src,main,java, and the folders inside, until you seeFirstPlugin.java. Also openresourcesto findplugin.yml.Project+first-pluginC:\Users\you\IdeaProjects\first-plugin.gradle.idea.runbuildgradlerunsrcmainjavacom.example.firstpluginCFirstPlugin1resourcesYplugin.yml2G.gitignoreKbuild.gradle.kts3Pgradle.properties>gradlew>gradlew.batKsettings.gradle.ktsExternal LibrariesScratches and ConsolesYour code lives under src/main/java, and plugin.yml under src/main/resources
These are the only two files you will change on this page:
- first-plugin-start/
- build.gradle.ktsThe build recipe. You will not change it today
- src/
- main/
- java/
- com/example/firstplugin/
- FirstPlugin.javaYour main class: the server starts it
- com/example/firstplugin/
- resources/
- plugin.ymlTells Paper the plugin's name, version and main class
- java/
- main/
The folder com/example/firstplugin may show up in IntelliJ as one line, com.example.firstplugin. That is the same thing, written with dots: a package, which is Java's word for a folder of code. Anatomy of a plugin project goes through every other file in the project.
Step 3: write the main class
Every plugin has exactly one main class. A class is a block of Java code with a name; the main class is the one Paper creates when your plugin starts. Double-click FirstPlugin.java to open it, and make it look exactly like this. If you used the starter download, it already does.
Where this file livesfirst-plugin-startsrcmainjavacomexamplefirstpluginFirstPlugin.java
The package com.example.firstplugin is the folder path com/example/firstplugin inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- first-plugin-start/
- src/main/
- java/com/example/firstplugin/Package com.example.firstplugin
- FirstPlugin.javayou are hereMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/firstplugin/Package com.example.firstplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1package com.example.firstplugin;2 3import org.bukkit.plugin.java.JavaPlugin;4 5public final class FirstPlugin extends JavaPlugin {6 7 @Override8 public void onEnable() {9 getLogger().info("Hello! FirstPlugin is up and running.");10 }11 12 @Override13 public void onDisable() {14 getLogger().info("Goodbye! FirstPlugin is shutting down.");15 }16}- Says which package (folder) this file lives in. It must match the real folders:
com/example/firstplugin. - Borrows
JavaPluginfrom the Paper API. Without this line, Java would not know whatJavaPluginmeans. - Creates a class called
FirstPlugin. The file name must be the class name plus.java.publiclets Paper see it;finalmeans no other class builds on top of it. - The key part: your class is a kind of
JavaPlugin. It gets everything a plugin needs (a logger, access to the server, and much more) for free. - An
annotation , a label for Java. It says "this replaces a method thatJavaPluginalready has". If you misspell the method name, Java now tells you instead of silently ignoring it. - A
method is a named list of instructions. Paper callsonEnableonce, when your plugin starts. This is where every plugin sets itself up. - Writes a line in the server console.
getLogger()gets your plugin's logger, and.info(...)writes an ordinary information line. The text between the double quotes is printed as-is. - Paper calls
onDisableonce, when the server stops. Big plugins save their data here. - Writes a farewell line as the server stops. The braces
{ }mark where each method and the class begin and end. Every{needs a matching}, and every instruction ends with a semicolon;.
Notice what is missing: you never call onEnable yourself, and there is no "start here" line. Paper is the program that runs. Your plugin is a set of methods that Paper calls at the right moments. That is the biggest difference between plugin code and the small Java programs in How code reads.
Now open plugin.yml. This small file is how Paper finds your main class inside the jar:
Where this file livesfirst-plugin-startsrcmainresourcesplugin.yml
Files in src/main/resources are copied into the jar exactly as they are. Paper looks for plugin.yml at the top of the jar.
- first-plugin-start/
- src/main/
- java/com/example/firstplugin/Package com.example.firstplugin
- FirstPlugin.javaMain class: Paper starts here (named as main in plugin.yml)
- resources/Files copied into the jar as they are
- plugin.ymlyou are hereTells Paper the plugin's name, version and main class
- java/com/example/firstplugin/Package com.example.firstplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1name: FirstPlugin2version: '1.0.0'3main: com.example.firstplugin.FirstPlugin4api-version: '26.3'5description: My first Paper plugin.- Your plugin's name, shown in the console and in
/plugins. Letters, digits and underscores only, no spaces. - Your plugin's version. The quotes keep it as text.
- The full name of your main class: package, a dot, then the class name. If this does not match your code exactly, including capital letters, the plugin will not load.
- The Paper version you wrote the plugin for. Paper uses it to decide how to treat your plugin.
- Optional. A short sentence about the plugin, shown by
/version FirstPlugin.
plugin.yml explained covers every other field you can put here.
Step 4: start a test server
You do not need to download or set up a Minecraft server. The project includes a run configuration called Run Paper Server: a saved button that builds your plugin, downloads Paper 26.3, and starts a server on your own PC with your plugin already loaded.
Pick Run Paper Server
At the top of the IntelliJ window there is a drop-down list next to a green triangle. Choose Run Paper Server in it.
1 2 3Current FileGRun Paper ServerGBuild Plugin JarEdit Configurations...Pick Run Paper Server, then press the green arrow Press the green Run button
A Run window opens at the bottom. The first time, the server is downloaded first, so give it a minute. Later starts take a few seconds.
Watch for your line
The console fills with text. Look for the lines that start with
[FirstPlugin]. When you seeDone, the server is ready.
This is what the first run looks like (many lines are left out where you see ...):
> Task :compileJava> Task :processResources> Task :classes> Task :jar> Task :runServerFetching latest Paper build for version 26.3...Latest build for 26.3 is 143.Downloading Paper 26.3 build 143...Starting Paper...[14:02:03 INFO]: [bootstrap] Loading Paper 26.3-143-main@ff3655a (2026-10-02T14:13:32Z) for Minecraft 26.3[14:02:03 INFO]: [PluginInitializerManager] Bukkit plugins (1): - FirstPlugin (1.0.0)...[14:02:07 WARN]: You have used the Paper command line EULA agreement flag....[14:02:08 INFO]: Starting Minecraft server on *:25565[14:02:08 INFO]: [FirstPlugin] Loading server plugin FirstPlugin v1.0.0[14:02:09 INFO]: Preparing level "world"...[14:02:11 INFO]: [FirstPlugin] Enabling FirstPlugin v1.0.0[14:02:11 INFO]: [FirstPlugin] Hello! FirstPlugin is up and running....[14:02:12 INFO]: Done (9.299s)! For help, type "help"Read it from the top. The > Task lines are Gradle: it compiles your code (turns your Java text into a form the computer can run) and packs it into a jar, the single file a plugin is shipped in. Then it downloads Paper and starts it. Paper lists the plugins it found, says it is loading yours, builds the world, and then enables it. "Enabling" is the moment Paper calls your onEnable method, which is why your "Hello!" line comes right after it.
A few lines look scary but are normal on a test server:
- The EULA lines. Every Minecraft server must accept Mojang's EULA (the rules for running a server). The test server accepts it with a setting in the build file, and Paper reminds you of that with these yellow warnings.
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called. This comes from a library inside Paper, not from your plugin. Ignore it.
The Run window is also a server console you can type into. Click in it, type plugins and press Enter. The server lists your plugin, in green because it is enabled:
plugins[14:02:20 INFO]: Server Plugins (1):[14:02:20 INFO]: Bukkit Plugins:[14:02:20 INFO]: - FirstPluginCommands typed in the console have no slash in front. In the game you would type /plugins.
Step 5: join your server
Leave the server running. Start Minecraft Java Edition 26.3, click Multiplayer, then Direct Connection, type localhost as the server address, and click Join Server. localhost means "this computer".
You arrive in a fresh world. Nothing special happens yet, because so far your plugin only writes to the console. Back in IntelliJ the console shows you joining:
[14:03:41 INFO]: Steve[/127.0.0.1:52134] logged in with entity id 87 at ([world]8.5, 64.0, 8.5)[14:03:41 INFO]: Steve joined the gameStep 6: greet players with a listener
Now make the plugin do something players can see. When something happens in the game, such as a player joining, Paper creates an event and offers it to every plugin that wants it. A listener is a class that says "tell me about these events". You need two changes: a new listener class, and one line in the main class that hands the listener to Paper.
Create the listener class
Make a new class
In the project tree, right-click the
com.example.firstpluginpackage and choose . TypeJoinListenerand press Enter. IntelliJ createsJoinListener.javanext toFirstPlugin.java, with the package line already filled in.Type the code
Make the file look exactly like the code below. When IntelliJ shows a name in red, click it and press Alt+Enter to add the missing
importline. If it offers several classes with the same name, pick the one fromorg.bukkit.
Where this file livesfirst-pluginsrcmainjavacomexamplefirstpluginJoinListener.java
The package com.example.firstplugin is the folder path com/example/firstplugin inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- first-plugin/
- src/main/
- java/com/example/firstplugin/Package com.example.firstplugin
- FirstPlugin.javaMain class: Paper starts here (named as main in plugin.yml)
- JoinListener.javayou are hereListener: reacts to events
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/firstplugin/Package com.example.firstplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1package com.example.firstplugin;2 3import org.bukkit.entity.Player;4import org.bukkit.event.EventHandler;5import org.bukkit.event.Listener;6import org.bukkit.event.player.PlayerJoinEvent;7 8public final class JoinListener implements Listener {9 10 @EventHandler11 public void onJoin(PlayerJoinEvent event) {12 Player player = event.getPlayer();13 player.sendRichMessage("<gold>Welcome to the server, " + player.getName() + "!");14 player.sendRichMessage("<gray>This message comes from your very first plugin.");15 }16}- Same package as the main class, because the file sits in the same folder.
- Four imports, one for each Paper type this file uses:
Player,EventHandler,ListenerandPlayerJoinEvent. - Marks this class as a listener. Without it,
registerEventsin the main class would not accept it and Java would report an error. - Tells Paper "call the method below when its event happens". A method without this label is never called.
- The part in brackets,
PlayerJoinEvent event, is what matters: it means "run me whenever a player joins". The nameonJoinis just a description; you could call it anything. - Asks the event which player joined and keeps that player in a
variable calledplayer, a named box for a value, so the next lines can use it. - Sends a chat message to this one player.
<gold>is aMiniMessage color tag. The+signs glue three pieces of text together: the start of the sentence, the player's name, and"!". - A second message, in gray. Each
sendRichMessagecall makes one chat line.
Gluing the name into the message is safe here because Minecraft names only contain letters, digits and underscores. For text that players type themselves, such as chat, you will use placeholders instead; MiniMessage shows how.
Register the listener
A listener does nothing until Paper knows about it. Open FirstPlugin.java and add one line at the start of onEnable:
Where this file livesfirst-pluginsrcmainjavacomexamplefirstpluginFirstPlugin.java
The package com.example.firstplugin is the folder path com/example/firstplugin inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- first-plugin/
- src/main/
- java/com/example/firstplugin/Package com.example.firstplugin
- FirstPlugin.javayou are hereMain class: Paper starts here (named as main in plugin.yml)
- JoinListener.javaListener: reacts to events
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/firstplugin/Package com.example.firstplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
1package com.example.firstplugin;2 3import org.bukkit.plugin.java.JavaPlugin;4 5public final class FirstPlugin extends JavaPlugin {6 7 @Override8 public void onEnable() {9 getServer().getPluginManager().registerEvents(new JoinListener(), this);10 getLogger().info("Hello! FirstPlugin is up and running.");11 }12 13 @Override14 public void onDisable() {15 getLogger().info("Goodbye! FirstPlugin is shutting down.");16 }17}- The new line. Read it from left to right: get the server, get its plugin manager (the part of Paper that looks after plugins), and register events.
new JoinListener()creates your listener;thismeans "this plugin", so Paper knows who owns it. - The log line from before. It now comes after the registration, so seeing it in the console also tells you the listener was registered without problems.
Try it
Your server is still running the old version of the plugin. Java code cannot be swapped into a running server safely, so you restart it:
- Click in the console, type
stopand press Enter. The server saves the world and shuts down. YouronDisableline appears on the way out:[FirstPlugin] Goodbye! FirstPlugin is shutting down. - Press the green Run button again. Gradle compiles your new code and builds a new jar before the server starts, so you never need to build by hand while testing.
- In Minecraft, join
localhostagain.
This message comes from your very first plugin.
Steve joined the game
That is your plugin talking. Only you see the gold and gray lines, because the code sends them to player, the player who joined.
The edit-run loop
What you just did is how every plugin developer works, all day: change the code, run the server, test in the game, stop the server, and go again.
Try one round now. Change <gold> to <aqua> in JoinListener, stop the server, run it, and join again. The welcome line is now aqua. A few habits make the loop smooth:
- Stop with
stop. Typingstopsaves the world cleanly. The red square Stop button in IntelliJ also works, but it can end the server abruptly, like pulling a plug, so usestopwhen you can. - Stay in the game. When the server stops, Minecraft shows "Connection Lost". Click Back to Server List; once the server is up again, join from the list.
- Read the console after every start. If your code has a problem, the console says so in red. Fixing it right away is much easier than guessing later.
- Never use reload commands to load new code. Stop and start the server instead. Build, install and test explains why.
Step 7: build the plugin jar
Run Paper Server builds a jar for its own use. When you want to give the plugin to a real server, build it on purpose. Pick Build Plugin Jar in the run drop-down and press the green Run button. Or open the terminal in IntelliJ () and type:
.\gradlew.bat build> Task :compileJava> Task :processResources> Task :classes> Task :jar> Task :assemble> Task :compileTestJava NO-SOURCE> Task :processTestResources NO-SOURCE> Task :testClasses UP-TO-DATE> Task :test NO-SOURCE> Task :check UP-TO-DATE> Task :buildBUILD SUCCESSFUL in 9s3 actionable tasks: 3 executedBUILD SUCCESSFUL means the jar is ready. You find it in the project's build\libs folder. In IntelliJ, open build and then libs in the project tree; in File Explorer, right-click the jar in IntelliJ and choose .
The jar's name is the project name plus the version: first-plugin-start-1.0.0.jar for the starter download, or first-plugin-1.0.0.jar if you used new-plugin.cmd. That single file is your whole plugin. Copy it into the plugins folder of any Paper 26.3 server, restart that server, and your welcome message works there too. Build, install and test covers installing in detail.
When something goes wrong
Almost every first-plugin problem is one of these. The console nearly always tells you which, so read it from the first red line.
| You see | What it means | Fix |
|---|---|---|
Minecraft 26.1 and newer requires running the server with Java 25 or above. | The server was started with an older Java. | Install Java 25 (see Your toolbox). Run Paper Server picks Java 25 automatically through the build file, so this usually appears when you start a server some other way. |
**** FAILED TO BIND TO PORT! and Address already in use | Another server is already running on port 25565, the network "door" Minecraft servers use. | You probably pressed Run twice. Stop the other server (check every tab in the Run window), then start again. |
Cannot find main class `com.example.firstplugin.Firstplugin' | The main: line in plugin.yml does not match your class. | Copy the package and class name exactly, capitals included. |
Your plugin is red in plugins, or missing from it | It failed to load or enable. | Scroll up in the console to the first ERROR line that mentions your plugin. |
| No welcome message, and no error | The listener is not registered, or @EventHandler is missing. | Check the registerEvents line and the annotation. |
| Red code everywhere in IntelliJ | Gradle has not finished importing, or a build file changed. | Wait for the progress bar, or open the Gradle window and press the reload button. |
For any other message, paste it into the Error Doctor, or look it up in the Error encyclopedia.
What you just did
You touched almost every part of plugin development in one page. Here is each piece in plain words, and where to learn it properly:
| What you did | What it really was | Learn more |
|---|---|---|
| Downloaded a starter folder | A Gradle project: your code plus the build recipe | Anatomy of a plugin project |
Wrote plugin.yml | The label that tells Paper your plugin's name and main class | plugin.yml explained |
Wrote class FirstPlugin extends JavaPlugin | A class that builds on Paper's plugin class | Classes and objects, Inheritance |
Filled in onEnable and onDisable | Methods Paper calls when your plugin starts and stops | The main class and plugin lifecycle |
Wrote JoinListener | A listener with an event handler for PlayerJoinEvent | Events and listeners |
Wrote "<gold>Welcome..." | Formatted text in MiniMessage | MiniMessage |
Used Player player = ... and + | A variable and text joining | Variables and types, Working with text |
Pressed Run Paper Server, typed stop, built the jar | The development loop | Build, install and test |
You can download the finished plugin from this page to compare it with yours, or open it in the Compile Lab to edit and compile it in your browser.
Make it yours
Change the welcome so it uses your server's name and your favorite colors. Then add a third line that tells players how to get help, for example "Type /help if you are lost". Stop, run, join and check the result.
Hint 1
Each sendRichMessage call is one chat line. Copy the line with <gray>, paste it under itself, and change the text.
Hint 2
Colors you can try: <red>, <green>, <aqua>, <light_purple>, <yellow>. Add <bold> after a color to make the text bold.
Show the solution
One possible answer. The text inside the quotes is up to you; what matters is that each line keeps its quotes, its closing bracket and its semicolon.
1Player player = event.getPlayer();2player.sendRichMessage("<aqua><bold>Welcome to Skyreach, " + player.getName() + "!");3player.sendRichMessage("<gray>This message comes from your very first plugin.");4player.sendRichMessage("<yellow>Type /help if you are lost.");This message comes from your very first plugin.
Type /help if you are lost.
How many players are online?
Change the welcome so it also tells the player how many players are online right now, counting themselves, and ends with a friendly line of your choice.
Hint 1
A player can reach the server with player.getServer(). Type a dot after it and look for a method about online players.
Hint 2
getOnlinePlayers() gives you all online players as a collection, and .size() on a collection tells you how many things are in it. Store the result in an int (a whole number) variable.
Show the solution
The new line counts the players first and keeps the number in online. Then the number is glued into the message with +, just like the name.
Where this file livesfirst-plugin-exercisesrcmainjavacomexamplefirstpluginJoinListener.java
The package com.example.firstplugin is the folder path com/example/firstplugin inside src/main/java: every dot in the package name is one folder. IntelliJ creates these folders for you when you make a new package.
- first-plugin-exercise/
- src/main/
- java/com/example/firstplugin/Package com.example.firstplugin
- FirstPlugin.javaMain class: Paper starts here (named as main in plugin.yml)
- JoinListener.javayou are hereListener: reacts to events
- resources/Files copied into the jar as they are
- plugin.ymlTells Paper the plugin's name, version and main class
- java/com/example/firstplugin/Package com.example.firstplugin
- build.gradle.ktsThe build recipe: Paper 26.3 API, Java 25, how the jar is made
- gradle.propertiesVersion numbers used by the build
- gradlew.batRuns Gradle on Windows without installing it
- settings.gradle.ktsThe project's name
- src/main/
Gray files come with the project template; you rarely edit them. Open the whole project in the Compile Lab, or download it from the project page.
10@EventHandler11public void onJoin(PlayerJoinEvent event) {12 Player player = event.getPlayer();13 int online = player.getServer().getOnlinePlayers().size();14 player.sendRichMessage("<gold>Welcome to the server, " + player.getName() + "!");15 player.sendRichMessage("<gray>Players online right now: <green>" + online);16 player.sendRichMessage("<aqua>Have fun and be nice!");17}- The player who just joined already counts as online, so on your test server this is 1.
- Two colors in one line: the label is gray, the number is green.
Players online right now: 1
Have fun and be nice!
Recap
- A plugin project is a folder with your Java code,
plugin.ymland a Gradle build recipe. Start from the starter download ornew-plugin.cmd. - The main class
extends JavaPlugin. Paper calls itsonEnablewhen the plugin starts andonDisablewhen it stops. plugin.ymltells Paper the plugin's name, version, main class andapi-version. Themainline must match your class exactly.- A listener class
implements Listener, has@EventHandlermethods, and must be registered inonEnable. - Run Paper Server builds your plugin and starts a test server; join it with
localhost. Stop it withstopand run again after every change. - Build Plugin Jar (or
.\gradlew.bat build) puts the finished jar inbuild\libs.
Quick quiz
When does Paper call your plugin's
onEnablemethod?The console showsEnabling FirstPlugin v1.0.0and then youronEnableline, once per server start. Player joins are events, handled by a listener instead.You wrote
JoinListenerperfectly, but nothing appears when you join, and the console shows no error. What is the most likely reason?Paper only calls listeners that were registered. The method name does not matter at all; the@EventHandlerlabel and thePlayerJoinEventparameter do.Your
plugin.ymlsaysmain: com.example.firstplugin.Firstpluginbut the class is calledFirstPlugin. What happens?Java names are case sensitive, soFirstpluginandFirstPluginare different names. Paper cannot find the class and gives up on the whole plugin.You changed the welcome message while the test server was running. How do you see the change in the game?
Run Paper Server rebuilds the jar every time it starts, so a restart picks up your new code. Reload commands do not load your new jar safely, and IntelliJ does not change a running server on its own.Where does Build Plugin Jar put the finished plugin?
Gradle writes its results to thebuildfolder, and jars go tobuild\libs. Plugins run on the server, so they never go into your game's folders.
Next steps
- Anatomy of a plugin project: what every other file in your project does.
- Build, install and test: put your jar on a real server and read the console like a pro.
- How code reads: start learning the Java behind the lines you just typed.
- Practice Arena: small challenges to try once you know a bit more.