PluginUtils is MCME's shared helper library for Paper plugins: chat messages with clickable parts, confirmation prompts, regions, a plot storage format, thin access to server internals, and small helpers for WorldEdit and Dynmap. It runs on the server as a plugin of its own, and other plugins compile against it and declare it as a dependency; they never bundle it. The current line is 2.0.x for Paper 26.2, and the latest release is 2.0.6.
- Repository: github.com/MCME/PluginUtils
- Artifact:
com.mcmiddleearth:PluginUtilson the Maven repository - Used by, among others: MCME-Architect (2.0.4), MCME-PvP (2.0.4), Guidebook (2.0.4) and MCME-Connect (2.0.2)
What is in it
All classes are under com.mcmiddleearth.pluginutil.
| Package | What it gives you |
|---|---|
message |
FancyMessage (chat lines with click and hover actions), MessageUtil, JSON message parsing, config-driven message templates (FancyMessageConfigUtil). Since 2.0.5 messages are sent as Adventure components, so clicks and tooltips work on 26.2, and paged lists end with a [‹ Prev] Page 2/3 [Next ›] line |
confirmation |
Chat confirmation prompts (ConfirmationFactory, ConfirmationPrompt) |
region |
Region maths: CuboidRegion, PrismoidRegion, SphericalRegion, with WorldEdit interop |
plotStoring |
The MCME plot format (MCMEPlotFormat, IStoragePlot, StoragePlotSnapshot): save and restore block regions with block entities, biomes and entities as compact NBT. MCME-Architect's copy and paste uses it |
nms |
Thin access to server internals (AccessNBT, AccessWorld, AccessServer, AccessInventory, NBTTagBuilder, ...), compiled against Paper's mojang-mapped dev bundle |
developer |
DevUtil, Debugable and the /dev command for per-plugin debug output |
| top level | BlockUtil, EntityUtil, PlayerUtil, StringUtil, NumericUtil, FileUtil, JSONUtil, TitleUtil, ConfigurationUtil, ReflectionUtil, LegacyMaterialUtil (pre-1.13 id and data to BlockData), WEUtil (WorldEdit), DynmapUtil (Dynmap) |
The plugin itself
The PluginUtils jar is a plugin (load: STARTUP) with one command:
| Command | Permission | Default | What it does |
|---|---|---|---|
/dev <plugin> [true \| false \| <level> \| r] |
pluginutil.developer |
op | Sends a plugin's debug output to you in chat, or to the console |
It soft-depends on ProtocolLib, Essentials, WorldEdit and dynmap. It has no config file.
Using it in a plugin
Compile against it, declare it in plugin.yml, and let the server provide it. Do not shade it.
Gradle
repositories {
maven { url = 'https://repo.mcmiddleearth.com/releases' }
}
dependencies {
compileOnly 'com.mcmiddleearth:PluginUtils:2.0.6'
// Only if your tests load PluginUtils classes (for example with MockBukkit):
testImplementation 'com.mcmiddleearth:PluginUtils:2.0.6'
}
Maven
<repositories>
<repository>
<id>mcme-releases</id>
<url>https://repo.mcmiddleearth.com/releases</url>
</repository>
</repositories>
<dependency>
<groupId>com.mcmiddleearth</groupId>
<artifactId>PluginUtils</artifactId>
<version>2.0.6</version>
<scope>provided</scope>
</dependency>
plugin.yml
depend: [PluginUtils]
Things to know:
- Build with JDK 25. PluginUtils 2.0.x is Java 25 bytecode. In Gradle, use a Java 25 toolchain; a build that targets older bytecode cannot resolve it ("only compatible with JVM runtime version 25 or newer").
- json-simple comes along. PluginUtils' one dependency is json-simple 1.1.1, which the Paper server also ships. Since 2.0.4 it is declared in the published POM and Gradle module, so it lands on your compile and test class paths but never in your jar.
- Don't use JitPack's coordinate (
com.github.MCME:PluginUtils) for anything you deploy. JitPack can build any commit, which is handy to try one, but its group id differs, and a build that also getscom.mcmiddleearth:PluginUtils(directly or through another MCME artifact) ends up with two copies. - Anything built against a version older than 2.0.2 breaks on 26.2. 2.0.0 and 2.0.1 were compiled against Minecraft 26.1.2, whose internals differ; such builds fail with
NoSuchMethodError: Entity.saveWithoutId. The public API has not changed since 2.0.2, so plugins built against 2.0.2 or later need no rebuild for a newer PluginUtils.
Building
./gradlew build
The build uses paperweight-userdev, which resolves paper-api and the server's internal classes from PaperMC's published dev bundle (26.2.build.111-stable). There is no local server jar to place by hand, so it builds on any machine and in CI. The first build downloads and decompiles the Paper server, which takes a few minutes; later builds use the cache. The jar lands in build/libs/.
- Gradle 9.0.0 comes with the wrapper; you don't need Gradle installed.
- paperweight-userdev is pinned to
2.0.0-beta.23, not its moving2.0.0-SNAPSHOT. Releases from beta.24 on need Gradle 9.7.1, so upgrade the plugin and the wrapper together. - Tests run on JUnit 6 and MockBukkit 4.116.1 (
mockbukkit-v26.2) against paper-api26.2.build.126-stable. The server jar from the dev bundle is kept off the test class path, because its service providers clash with MockBukkit's. - The jar is reproducible across systems.
processResourcesfills${project.version}intoplugin.ymland writes it with LF line endings, so a Windows build gives the same jar as CI on Linux.
CI (.github/workflows/build.yml) builds every push to master and development, every pull request and every tag, on ubuntu-26.04 with Temurin 25.
Branches and releases
| Branch | What it holds |
|---|---|
master |
Releases, 2.0.x. It moves only when a version is released, through a pull request from development |
development |
Where the work happens, through pull requests |
pluginutils-26.2, publish-2.0.2, 1.13 |
History: where 2.0.x was ported, where 2.0.2 was published from, and a 2018 branch |
Both master and development are protected. The legacy 1.9.x line (Paper 1.21.x, a Maven build that needed a local server jar) ends at commit f17ced6.
To release (from the README):
- On a branch from
development, setversioninbuild.gradle, move the[Unreleased]notes inCHANGELOG.mdinto a dated section, and update the version in the README. Commit it asrelease: PluginUtils X.Y.Z — <what changed>and open a pull request intodevelopment. - When CI is green and the pull request is merged, tag the release commit with an annotated, bare tag (
2.0.6, notv2.0.6) and push it. CI then publishes that version to the Maven repository.releasesrefuses to overwrite a version, so check the published POM, module and jar afterwards. - Open a pull request from
developmentintomaster. - On
development, start the next version:version = 'X.Y.(Z+1)-SNAPSHOT'.
Release history (2.0.x)
| Version | Date | What changed |
|---|---|---|
| 2.0.0 | 2026-08-11 | Withdrawn: the jar's plugin.yml had an unfilled name and Paper refused to load it |
| 2.0.1 | 2026-08-11 | Fills in the plugin.yml tokens |
| 2.0.2 | 2026-08-11 | Built against Paper 26.2 instead of 26.1.2; the first release that works on 26.2 |
| 2.0.3 | 2026-09-21 | Registers the /dev permission, fixes the dynmap soft dependency and other plugin.yml keys Paper ignored |
| 2.0.4 | 2026-09-23 | No code changes: json-simple is declared in the published POM and module, so consumers' MockBukkit tests find it |
| 2.0.5 | 2026-10-02 | Messages as Adventure components (clicks and tooltips work again on 26.2); new list pager line; first tests |
| 2.0.6 | 2026-10-23 | Hover text wraps words too long for one line; jars built on Windows and in CI are identical |
CHANGELOG.md has the full notes.