Hot reload for Bukkit/Spigot/Paper plugins. Save your code, it's live on the server a second later. No restart.
Weld is a dev tool. Don't run it on a production server.
If you write plugins you know the loop. Edit code, build jar, stop server, copy jar, start server, log in, walk back to your test spot, realize you had a typo, do it all again. Each cycle is like 30 seconds on a good day. Over an afternoon it's brutal.
Weld cuts that down to "save file, wait ~1 second".
There are two parts.
-
A server plugin (
weld-plugin) that watches a folder and reloads any jar you drop into it. The reload is proper, not/reloadhacky. It unregisters listeners, cancels scheduled tasks, kills the old classloader, then loads the new jar and calls onEnable on it. -
A Gradle plugin (
weld-gradle) that your project adds. When you runweldDeployit builds your jar and copies it into Weld's watch folder on the server. Combined withgradle -t(continuous build) you get save-to-live automatically.
- Grab
weld-plugin-0.1.0.jarfrom the releases page. - Drop it in
plugins/. - Start the server. Weld will make
plugins/Weld/incoming/which is the folder it watches.
Add this to build.gradle.kts:
plugins {
id("dev.leoon.weld") version "0.1.0"
}
weld {
mode.set("local")
localPath.set("/full/path/to/server/plugins/Weld/incoming")
jarTask.set("jar") // use "shadowJar" if you use shadow
}Then:
./gradlew weldDeploy
Check the server console. Should say something like Reloaded YourPlugin in 87ms.
Run this in a terminal and leave it open:
./gradlew -t weldDeploy
The -t flag puts gradle in continuous mode. Every time you save a file it rebuilds and redeploys. That's the save-to-live loop.
If you don't want a terminal running you can also add weldDeploy to IntelliJ's "run on save" actions.
| Command | What it does |
|---|---|
/weld status |
shows the watched dir and config |
/weld list |
lists jars sitting in the incoming folder |
/weld reload <jar> |
manually reload a jar |
/weld version |
prints version |
Permission is weld.admin, defaults to op.
plugins/Weld/config.yml:
enabled: true
broadcast-reloads: true
debounce-ms: 400debounce-ms is how long the watcher waits between duplicate file events from your IDE. If you get double reloads, bump it up.
Being real about the limits.
- Does not save your in memory state. If you have a HashMap cache, it's empty after reload. Store stuff on disk if you need it to survive.
- Can't reload itself. Don't drop the Weld jar in the incoming folder.
- If plugin B depends on plugin A and you reload A, B still has references to A's old classes. Reload B too, or just restart if things get weird.
- Native libs (.so / .dll) can't be reopened. JVM limitation. If your plugin loads native code, reload will fail until next restart.
- It's a dev tool. Reloads are good enough for dev work, not perfect. If something ends up in a weird state, restart the server, it's fine.
If your dev server is on another machine:
- Mount the remote plugins folder over SSHFS or mutagen and use
localmode on the mount. - Or rsync/scp the jar yourself after build. The Weld watcher on the other end picks it up.
- Native SFTP mode isn't in this release. Maybe later.
git clone https://github.com/Leoon-X/weld.git
cd weld
./gradlew build
Needs JDK 17+. Compiles against Paper API 1.20.1, works on 1.20.1 and later.
Output jars:
weld-plugin/build/libs/weld-plugin-0.1.0.jarweld-gradle/build/libs/weld-gradle-0.1.0.jar
PRs welcome. If it's a feature, open an issue first so we can talk about it before you write a lot of code.
Bug reports should include Paper version, JDK version, which plugin you were reloading, and the full stack trace.
MIT. Do whatever.
The reflection tricks for unloading plugins aren't new. PlugMan and similar projects have been doing this for years. Weld just wraps it in a file watcher and gradle plugin so the dev loop is automatic.