Paper Plugin Guide
File mode0

Start here

Build, install and test

The development loop: build a jar, put it on a server, restart, read the console.

Beginner27 min read

Writing code is half the job; the other half is building it, getting it onto a server, and reading what the server says about it. On this page you will build jars from IntelliJ and from a terminal, install a plugin on a real server the right way, get more out of the test server, read the console and its stack traces, and check a plugin properly before you give it to anyone.

You should have a working project from Your first plugin. If you want to know what each file in it does, read Anatomy of a plugin project first.

Two ways to run your plugin

Every change you make ends up as a new jar. That jar can go two places: the test server on your own PC, which you use dozens of times a day, or a real server where players are, which you update when a version is ready.

Your code src/main/... Gradle build compile and pack The jar build/libs/ Test server (Run Paper Server) Builds the jar for you Loads it straight from build/libs Lives in the run folder Restart it after every change Real server Build the jar yourself Copy it into the plugins folder Remove the old version's jar Restart the server, never reload
The same jar, two destinations: the test server picks it up by itself, a real server needs you to copy it and restart

Building the jar

Building means running the Gradle task called build. A task is one job Gradle knows how to do, such as compiling, packing the jar or starting the test server. There are three ways to run it, and they all do the same thing.

Pick Build Plugin Jar in the run drop-down at the top of IntelliJ and press the green Run button. The output appears in the Run window at the bottom.

Open the Gradle tool window (the elephant icon on the right edge of IntelliJ), open Tasksbuild and double-click build. The same window lists every other task too, such as clean under build and runServer under run paper.

Every Gradle task, ready to double-click

Open IntelliJ's terminal with ViewTool WindowsTerminal. It starts in your project folder, so you can type the command straight away:

Terminal
 .\gradlew.bat build

The .\ at the start means "the file in this folder". In a plain PowerShell window, first go to the project folder with cd, for example cd C:\Users\YourName\IdeaProjects\first-plugin.

A successful build looks like this. Each > Task line is one step: compile the Java code, copy the resources, pack the jar. Steps that have nothing to do (there are no tests yet) say NO-SOURCE or UP-TO-DATE.

Terminal
 .\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 executed

The jar is in build\libs, named after the project and its version: first-plugin-1.0.0.jar. The name comes from rootProject.name in settings.gradle.kts and version in gradle.properties. You may also see a note that "Deprecated Gradle features were used". It is a warning about the build file's style, not a problem with your plugin; Anatomy of a plugin project explains them.

When the build fails

If your code has a mistake, the build stops at compileJava and prints BUILD FAILED. Here the semicolon at the end of a line is missing:

Terminal
 .\gradlew.bat build> Task :compileJava FAILEDC:\Users\YourName\IdeaProjects\first-plugin\src\main\java\com\example\firstplugin\FirstPlugin.java:10: error: ';' expected        getLogger().info("Hello! FirstPlugin is up and running.")                                                                 ^1 errorFAILURE: Build failed with an exception.* What went wrong:Execution failed for task ':compileJava' (registered by plugin class 'org.gradle.api.plugins.JavaBasePlugin').> Compilation failed; see the compiler output below.BUILD FAILED in 1s

Read the first error: line. It names the file, the line number after the colon (:10), and what Java expected. The ^ on the line below points at the exact spot. Fix that one error and build again; one mistake often causes several error lines, and they disappear together. No new jar is made when the build fails, so the old jar in build\libs is still the old code.

Installing on a real server

A real server is any Paper 26.3 server that is not your test server: one on another PC, a rented host, or a friend's server. Installing a plugin is always the same few steps.

  1. Stop the server

    Type stop in the server console, or use the stop button of your hosting panel. Wait until it has fully shut down.

  2. Copy the jar into the plugins folder

    Every Paper server has a plugins folder next to its server.properties. Copy your jar from build\libs into it.

    A server's plugins folder with your jar in it
  3. Remove the old version

    If an older jar of the same plugin is in the folder, delete it. With two jars of the same plugin, Paper refuses to choose properly and prints an error (see below).

  4. Start the server and read the console

    Look for Enabling FirstPlugin v1.0.0 and no ERROR lines that mention your plugin. Then check in the game.

Two in-game commands confirm the install. /plugins lists every plugin, green when enabled and red when something went wrong. /version FirstPlugin shows which version is running, which matters when you are not sure the new jar was picked up.

Server Plugins (1):
Bukkit Plugins:
- FirstPlugin
FirstPlugin version 1.0.0
My first Paper plugin. It greets players when they join.

Both commands also work in the server console, without the slash. That is the easiest place to run them on a hosted server.

If two jars of the same plugin sit in the folder, you see this at startup, and you cannot be sure which version is running:

Server console
[14:10:02 ERROR]: [ModernPluginLoadingStrategy] Ambiguous plugin name 'FirstPlugin' for files 'plugins\first-plugin-1.0.0.jar' and 'plugins\first-plugin-0.9.0.jar' in 'plugins'

On a hosting panel

Most rented servers use a web panel, often Pterodactyl or one based on it. The names of the buttons vary, but the steps are the same: stop the server in the console page, open the Files page, go into the plugins folder, use Upload to send your jar (and delete the old one), then start the server and watch the console page.

Uploading a jar into the plugins folder on a hosting panel

Why never reload

Old tutorials say to type /reload after copying a new jar. Do not. Restart the server instead, every time.

Reloading tries to switch plugins off and back on inside a running server. Your plugin's old objects, scheduled tasks and saved values can stay behind in memory, other plugins may keep pointing at your old classes, and players who are online keep whatever the old code gave them. The result is bugs that only happen after a reload, memory that keeps growing, and hours spent hunting problems that are not in your code. Paper itself warns against it.

In Paper 26.3, the plugin reload command is /bukkit:reload, and it asks for confirmation:

Server console
 bukkit:reload[14:12:40 INFO]: CONSOLE: Are you sure you wish to reload your server? This command will be removed soon. Doing so may cause bugs and memory leaks. It is recommended to restart instead of using /bukkit:reload. To confirm, please type /bukkit:reload confirm

Plain /reload on a 26.3 server is Minecraft's own command, which reloads data packs only. It does not touch plugins at all, so it will not load your new jar either. Plugins that register commands with Paper's newer command system even block plugin reloads completely. The short version: stop, replace the jar, start.

The test server in depth

The Run Paper Server button runs the Gradle task runServer from the run-paper plugin. Knowing what it does makes the test server much more useful.

What it does when you press Run

  1. It builds your jar, exactly like build does (without the test steps).
  2. It downloads the newest Paper build for the version in gradle.properties, or reuses the copy it downloaded before:
    Run: Run Paper Server
    > Task :runServerLocated Paper 26.3 build 143 in local cache.Starting Paper...
  3. It starts Paper in the run folder and tells it to load your jar straight from build\libs. That is why your jar never appears in run\plugins.

The run folder

After the first start, run looks like a normal server folder, and you can change it like one:

  • run/
    • plugins/Data folders of your plugins (config.yml lives here). Drop other plugin jars here to test with them
    • logs/latest.log for this run, older runs as .log.gz files
    • world/The test world, plus world_nether and world_the_end
    • server.propertiesPort, game mode, online mode, view distance and more
    • eula.txtOnly matters for servers started without the EULA flag
    • ops.jsonPlayers you made operator with op YourName
  • Test with other plugins: put their jars in run\plugins. They load next to yours, which is how you test a plugin that works together with, say, LuckPerms.
  • Change server settings: stop the server, edit run\server.properties (for example gamemode=creative), and start again.
  • Start over: stop the server and delete the run folder. The next run creates a fresh server and a new world.

The EULA flag

A Minecraft server only starts after its owner accepts Mojang's EULA, the end user license agreement for running a server. A real server writes eula.txt and stops until you change eula=false to eula=true. The test server skips that step because build.gradle.kts starts it with -Dcom.mojang.eula.agree=true, and Paper says so in yellow:

Run: Run Paper Server
[14:02:07 WARN]: You have used the Paper command line EULA agreement flag.[14:02:07 WARN]: By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA).[14:02:07 WARN]: If you do not agree to the above EULA please stop your server and remove this flag immediately.

Changing the Minecraft version

The test server's version is minecraftVersion in gradle.properties. The Paper API your code compiles against is paperVersion. Keep them about the same Minecraft version: when a new version comes out, change both, press the reload button that IntelliJ shows for Gradle files, and run again. If you have the paper-templates folder, update-paper-version.ps1 finds the newest Paper API build and writes it in for you.

The Debug button

Next to the green Run button is a green bug. It starts the same test server, but with IntelliJ's debugger attached. Click in the gray strip to the left of a line of code to set a red breakpoint; when the server reaches that line, everything pauses and IntelliJ shows you the values of all variables at that moment. Debugging like a pro teaches it step by step.

The server paused at a breakpoint, showing the variables

Reading the server console

The console is the server talking to you. Every line has the same four parts:

[14:02:11 WARN]: [StartupCheck] online-mode is off. Anyone can... When your PC's clock Level how serious Who name from plugin.yml What the text your code logged INFO Normal news getLogger().info(...) WARN Looks wrong, still runs getLogger().warning(...) ERROR Something failed getLogger().severe(...)
The parts of a console line, and the three levels you will see most

Your plugin writes these lines through its logger. This small plugin checks a few server settings when it starts and uses all three levels, so you can see what each one looks like:

StartupCheckPlugin.javaCompiles on Paper 26.3Compile Lab
Where this file livesbuild-and-run-consolesrcmainjavacomexamplebuildandrunconsoleStartupCheckPlugin.java

The package com.example.buildandrunconsole is the folder path com/example/buildandrunconsole 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.

  • build-and-run-console/
    • src/main/
      • java/com/example/buildandrunconsole/Package com.example.buildandrunconsole
        • StartupCheckPlugin.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
    • 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

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.buildandrunconsole;2 3import org.bukkit.plugin.java.JavaPlugin;4 5public final class StartupCheckPlugin extends JavaPlugin {6 7    @Override8    public void onEnable() {9        String version = getPluginMeta().getVersion();10        String minecraft = getServer().getMinecraftVersion();11        getLogger().info("StartupCheck " + version + " is running on Minecraft " + minecraft + ".");12 13        if (!getServer().getOnlineMode()) {14            getLogger().warning("online-mode is off. Anyone can join with any name.");15        }16 17        if (getServer().getMaxPlayers() < 2) {18            getLogger().severe("max-players is below 2, so nobody can play together.");19        }20    }21 22    @Override23    public void onDisable() {24        getLogger().info("StartupCheck stopped.");25    }26}
  1. The version from plugin.yml. Logging it at startup tells you at a glance which version of your jar the server is running.
  2. Asks the server which Minecraft version it runs, as text such as 26.3.
  3. An INFO line: normal news.
  4. The ! means "not": this runs when online mode is off.
  5. A WARN line: something looks wrong, but the plugin keeps going.
  6. An ERROR line. Java calls this level "severe", the console prints it as ERROR.

On a test server with online-mode=false and max-players=1 in server.properties, the console shows:

Run: Run Paper Server
[14:20:09 INFO]: [StartupCheck] Enabling StartupCheck v1.0.0[14:20:09 INFO]: [StartupCheck] StartupCheck 1.0.0 is running on Minecraft 26.3.[14:20:09 WARN]: [StartupCheck] online-mode is off. Anyone can join with any name.[14:20:09 ERROR]: [StartupCheck] max-players is below 2, so nobody can play together.

When you scan a long console, look for your plugin's name in brackets, and for WARN and ERROR. IntelliJ and most panels color them yellow and red. Use INFO for things that are good to know, WARN for things an admin should look at, and ERROR only when something really failed; a plugin that fills the console with red trains people to ignore it.

Stack traces

When your code crashes, Java prints a stack trace: the error, followed by the list of methods that were running when it happened. Here a plugin's onEnable read a setting that does not exist and then used the empty result:

FirstPlugin.java (inside onEnable)Has a mistake
1String greeting = getConfig().getString("greeting");2getLogger().info(greeting.toUpperCase());
Run: Run Paper Server
[14:22:30 INFO]: [FirstPlugin] Enabling FirstPlugin v1.0.0[14:22:30 ERROR]: Error occurred while enabling FirstPlugin v1.0.0 (Is it up to date?)java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because "greeting" is null	at first-plugin-1.0.0.jar//com.example.firstplugin.FirstPlugin.onEnable(FirstPlugin.java:11) ~[?:?]	at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:280) ~[paper-api-26.3.build.143-beta.jar:?]	at io.papermc.paper.plugin.manager.PaperPluginInstanceManager.enablePlugin(PaperPluginInstanceManager.java:201) ~[paper-26.3.jar:26.3-143-ff3655a]	...	at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:593) ~[paper-26.3.jar:26.3-143-ff3655a]	at net.minecraft.server.MinecraftServer.initPostWorld(MinecraftServer.java:641) ~[paper-26.3.jar:26.3-143-ff3655a]	...	at java.base/java.lang.Thread.run(Thread.java:1474) ~[?:?][14:22:30 INFO]: [FirstPlugin] Disabling FirstPlugin v1.0.0

It looks like a wall of text, but you only need three things from it:

  1. The headline: Error occurred while enabling FirstPlugin. The crash happened inside your onEnable, so Paper switched the plugin off again right after (the Disabling line). The "(Is it up to date?)" part is a fixed phrase Paper always adds; it does not mean your plugin is outdated.
  2. The exception line: NullPointerException: Cannot invoke "String.toUpperCase()" because "greeting" is null. Java says exactly what went wrong: greeting was empty (null), because the config has no greeting setting.
  3. The first at line in your package: com.example.firstplugin.FirstPlugin.onEnable(FirstPlugin.java:11). That is the file and line number to open. Everything below it is Paper and Java calling your code, which you can ignore.

Some stack traces have a Caused by: section further down; then the last Caused by is usually the real reason. Null, exceptions and stack traces explains exceptions properly, and the Error Doctor reads a pasted stack trace for you.

Log files

Everything in the console is also saved in the server's logs folder. logs\latest.log is the current run. When the server starts again, the previous log is packed into a file named after the date, such as 2026-10-03-1.log.gz (a .gz file is compressed; 7-Zip or most zip tools open it). When a player says "it broke last night", these files are where you look, and they are what you share when you ask someone for help.

Hot reload: what it can and cannot do

Restarting for every change takes a few seconds, and that is the normal way to work. While the server runs with the Debug button, IntelliJ can sometimes swap changed code into the running server without a restart. This is called HotSwap: after you edit a method and build (Ctrl+F9), IntelliJ offers to reload the changed classes, or you choose RunDebugging ActionsReload Changed Classes.

The Java runtime that runs Paper only allows small swaps:

ChangeHotSwap works?
Changing code inside an existing method, such as the text of a messageYes. The next time the method runs, it uses the new code.
Adding or removing a method, a field or a classNo. Restart.
Changing a method's name or parametersNo. Restart.
Changing plugin.yml or config.yml defaultsNo. Restart.
Changing onEnableThe swap works, but onEnable already ran and does not run again. Restart.

So HotSwap is handy for tuning a message or a number inside an event handler. For everything else, stop and run again; nobody restarts the test server less often than they need to.

Versioning your plugin

A version number tells you and your server owners which build is which. Plugins usually use three numbers, MAJOR.MINOR.PATCH: raise the last one for a bug fix (1.0.1), the middle one for new features (1.1.0), and the first one for changes that break old setups, such as a new config layout (2.0.0). Releasing and sharing your plugin goes deeper.

In the guide's starter projects the version is written in two places, and you change both:

  • version=1.0.0 in gradle.properties names the jar.
  • version: '1.0.0' in plugin.yml is what the server shows in the console and in /version.

To keep it in one place, let Gradle write the version into plugin.yml while it builds. Add this block inside tasks { } in build.gradle.kts (it is the same block the paper-templates projects use):

build.gradle.kts (inside tasks)
1processResources {2    val properties = mapOf("version" to project.version, "apiVersion" to minecraftVersion)3    inputs.properties(properties)4    filteringCharset = Charsets.UTF_8.name()5    filesMatching(listOf("plugin.yml", "paper-plugin.yml")) {6        expand(properties)7    }8}
  1. Changes the task that copies src/main/resources into the jar.
  2. The values to fill in: the project version from gradle.properties, and the Minecraft version for api-version.
  3. Tells Gradle to redo the copy when one of these values changes. Without it, a new version number could be skipped.
  4. Only these files get their placeholders filled.

Then use placeholders in plugin.yml:

plugin.yml
1name: FirstPlugin2version: '${version}'3main: com.example.firstplugin.FirstPlugin4api-version: '${apiVersion}'

Now changing version in gradle.properties updates both the jar name and the version the server shows.

Keep your old jars. Before you install a new version on a real server, copy the jar you are replacing into a folder such as releases on your PC (outside the project's build folder, which clean wipes). If the new version has a bug, going back is one file copy away.

Checklist before you share a plugin

Run through this list before a plugin goes to a real server or to another person. It catches the problems that are embarrassing to hear about from players.

  1. Raise the version and make sure plugin.yml shows the same number.
  2. Build cleanly: .\gradlew.bat clean build ends with BUILD SUCCESSFUL.
  3. Start on a fresh server: stop the test server, delete run, and run again. This is how a new server owner sees your plugin: no old config files, no old data.
  4. Read the whole startup console: your Enabling line, no WARN or ERROR from your plugin, and a correct /version.
  5. Test every feature in the game, as an operator and as a normal player (use deop YourName in the console). Permissions bugs only show up for non-operators.
  6. Test the restart: stop and start the server once more and check that saved data and changed config values survive.
  7. Check logs\latest.log for errors that scrolled past while you were playing.
  8. Keep the jar in your releases folder, with a line or two about what changed.
Try it

Break plugin.yml on purpose

Learning to read an error is easier when you know the cause. In your first-plugin project, change the main: line in plugin.yml so the class name has a small capital-letter typo: com.example.firstplugin.Firstplugin. Press Run Paper Server. Does the build succeed? What does the console say, and what color is your plugin in plugins? Then fix it.

Hint 1

The build only compiles Java and copies plugin.yml; it never checks what main: says. The problem shows up when the server tries to load the plugin, early in the startup.

Hint 2

Search the console for ERROR, or for the word main.

Show the solution

The build succeeds. The server starts too, but your plugin does not load:

Run: Run Paper Server
[14:30:01 ERROR]: [ModernPluginLoadingStrategy] Could not load plugin 'first-plugin-1.0.0.jar' in folder 'C:\Users\YourName\IdeaProjects\first-plugin\build\libs'org.bukkit.plugin.InvalidPluginException: Cannot find main class `com.example.firstplugin.Firstplugin'	at org.bukkit.plugin.java.PluginClassLoader.<init>(PluginClassLoader.java:84) ~[paper-api-26.3.build.143-beta.jar:?]	at io.papermc.paper.plugin.provider.type.spigot.SpigotPluginProvider.createInstance(SpigotPluginProvider.java:125) ~[paper-26.3.jar:26.3-143-ff3655a]	...Caused by: java.lang.ClassNotFoundException: com.example.firstplugin.Firstplugin	at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:208) ~[paper-api-26.3.build.143-beta.jar:?]	...

Read it with the three-step method: the headline says Paper could not load the jar; the exception says it cannot find the main class com.example.firstplugin.Firstplugin; and Caused by: ClassNotFoundException confirms that no class with that exact name exists. None of the at lines are in your code, because your code never ran. There is no Enabling FirstPlugin line, no "Hello!", and plugins shows FirstPlugin in red.

The fix is to make main: match the class exactly, capital P included: main: com.example.firstplugin.FirstPlugin. Run again and the plugin is green.

Try it

One more startup check

Add a check to StartupCheckPlugin: read the server's view distance and log a warning if it is above 12 (high view distances cause lag), or an info line saying it looks good. Raise the plugin's version to 1.1.0, run the test server and find your new line in the console.

Hint 1

Type getServer().getView and let autocomplete show you the method that returns the view distance as an int.

Hint 2

Store it in a variable, then use if (viewDistance > 12) { ... } else { ... } with warning in one branch and info in the other.

Show the solution

getServer().getViewDistance() returns the view-distance from server.properties. The new lines go at the end of onEnable:

StartupCheckPlugin.javaCompiles on Paper 26.3Compile Lab
Where this file livesbuild-and-run-exercisesrcmainjavacomexamplebuildandrunexerciseStartupCheckPlugin.java

The package com.example.buildandrunexercise is the folder path com/example/buildandrunexercise 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.

  • build-and-run-exercise/
    • src/main/
      • java/com/example/buildandrunexercise/Package com.example.buildandrunexercise
        • StartupCheckPlugin.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
    • 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

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.

7@Override8public void onEnable() {9    String version = getPluginMeta().getVersion();10    String minecraft = getServer().getMinecraftVersion();11    getLogger().info("StartupCheck " + version + " is running on Minecraft " + minecraft + ".");12 13    if (!getServer().getOnlineMode()) {14        getLogger().warning("online-mode is off. Anyone can join with any name.");15    }16 17    if (getServer().getMaxPlayers() < 2) {18        getLogger().severe("max-players is below 2, so nobody can play together.");19    }20 21    int viewDistance = getServer().getViewDistance();22    if (viewDistance > 12) {23        getLogger().warning("view-distance is " + viewDistance + ". Values above 12 can cause lag.");24    } else {25        getLogger().info("view-distance is " + viewDistance + ". Looks good.");26    }27}
  1. Read once and kept in a variable, because it is used twice: in the check and in the message.
  2. The check. Exactly one of the two branches runs.

And the version in plugin.yml:

plugin.ymlCompiles on Paper 26.3Compile Lab
Where this file livesbuild-and-run-exercisesrcmainresourcesplugin.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.

  • build-and-run-exercise/
    • src/main/
      • java/com/example/buildandrunexercise/Package com.example.buildandrunexercise
        • StartupCheckPlugin.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
    • 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

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: StartupCheck2version: '1.1.0'3main: com.example.buildandrunexercise.StartupCheckPlugin4api-version: '26.3'5description: Checks a few server settings at startup, including the view distance.
  1. Raised to 1.1.0, because this is a new feature. Remember gradle.properties too, unless you use the processResources block.

A new Paper server has a view distance of 10, so the console shows:

Run: Run Paper Server
[14:35:12 INFO]: [StartupCheck] StartupCheck 1.1.0 is running on Minecraft 26.3.[14:35:12 INFO]: [StartupCheck] view-distance is 10. Looks good.

Recap

  • Build with Build Plugin Jar, the Gradle window, or .\gradlew.bat build. The jar is build\libs\<project>-<version>.jar.
  • When a build fails, read the first error: line: file, line number, and what Java expected.
  • To install: stop the server, copy the jar into plugins, delete the old jar, start, and check the console, /plugins and /version.
  • Never reload plugins. Restart the server.
  • The test server lives in run, loads your jar from build\libs, and accepts the EULA with a flag; delete run for a fresh server.
  • Console lines show time, level (INFO, WARN, ERROR), plugin and message. In a stack trace, find the exception line and the first at line in your own package.
  • HotSwap only changes code inside existing methods; restarting is normal.
  • Raise the version for every release, keep old jars, and test on a fresh server before sharing.

Quick quiz

  1. You copied version 1.1.0 of your plugin into a real server's plugins folder while it was running. What should you do next?

  2. In a stack trace, which line usually tells you where to look in your own code?

  3. Your plugin.yml's main: line has a typo. When do you find out?

  4. Which log level should a plugin use for "the config file has an unknown sound name, using the default instead"?

  5. While debugging, you added a brand-new method to your listener. Can HotSwap load it into the running server?

  6. Where is the test server's log for the current run?

Next steps