Repository navigation
ServerMatcher
Basti edited this page Sep 27, 2026
·
2 revisions
Guardrail for Paper plugins: declare which Minecraft versions you support and decide whether to warn or auto-disable when the server falls outside that list.
- Match explicit Minecraft versions (
1.21.1,1.21.10, etc.). - Define inclusive ranges (e.g.,
1.20.5through1.21.10). - Allow a whole
major.minorseries (e.g.,26.3accepts26.3,26.3.1, …) so hotfix releases stay supported automatically. - Combine ranges, series, and single versions in the same matcher.
- Choose the fallback policy: warn and continue, or log an error and disable the plugin.
- Hook into mismatches with a custom consumer if you need additional reporting/telemetry.
- Fluent builder that mixes ranges + singles with optional open-ended bounds.
- Built-in
MatchResultsummary for logging and telemetry. - Automatic enforcement mode that logs + disables on unsupported servers when configured.
-
Minecraft version only, on Paper: it reads
Bukkit.getMinecraftVersion(), a Paper method. A server without it, such as Spigot, counts as unsupported (Minecraft versionunknown) whatever the rules say. The server brand is shown but never checked otherwise, so it can't exclude forks or require a Paper build. - Allow rules only: rules are combined with "or", and nothing can be excluded. Without any rule every Paper server counts as supported.
-
Exact versions compare as text:
allowVersion("26.3")doesn't match26.3.0. -
Ranges are inclusive and use VersionComparator, with its limits: a maximum of
26.3rejects26.3.1(use a series for hotfixes), and prereleases rank below their release in Minecraft's order (26.3-pre1<26.3-rc1<26.3). A minimum above the maximum is accepted and never matches. A bound that isn't a version (e.g.latest) reads as0(see VersionComparator): as a minimum it lets every version through, as a maximum none. -
Series compare the first two dot-separated parts as text, after cutting a prerelease suffix:
allowMinorSeries("26")only matches a server that reports exactly26. Prereleases belong to their series (26.3-pre1and26.3-rc1are in26.3, unlike in a range), and snapshots (26w14a) never match a series. -
Silently ignored: a blank
allowVersionorallowMinorSeries, andincompatibleAction(null), which keeps the default. -
ERROR_AND_DISABLEdisables right away, insideenforce(), whileonEnable()is still running: youronDisable()runs first, and the code afterenforce()still runs, so return right after it (see the example). -
builder(...)needs aJavaPlugin, and its console lines are in English.
- Build a matcher inside
onEnable()using explicit versions, ranges, and/or minor series. - Decide how to react via
incompatibleAction(...)(warn or disable) and optional mismatch consumer. - Call
enforce()during startup; use the returnedMatchResultfor custom messaging.
| Accessor | Meaning |
|---|---|
supported() |
true when the running server matches your allow list. |
serverName() |
Brand reported by Bukkit (e.g., Paper). |
minecraftVersion() |
Detected MC version (e.g., 1.21.1). |
supportedDescription() |
Human-readable summary of your allowed versions. |
message() |
Pre-built reason for logging or error screens (empty string when supported). |
| Method | Description |
|---|---|
allowVersion(String) |
Adds an exact Minecraft version (from Bukkit.getMinecraftVersion()). |
allowVersions(Collection<String>) |
Bulk add multiple exact versions. |
allowRange(String min, String max) |
Adds an inclusive range. Pass null (or blank) for open-ended bounds (e.g., >= 1.20); both blank adds nothing. |
allowMinorSeries(String) |
Allows every version whose first two segments match (e.g., "26.3" or "26.3.1" → 26.3.x). Prefer it over allowRange with equal min/max, which rejects hotfixes. |
incompatibleAction(IncompatibleAction) |
WARN_AND_CONTINUE logs a warning and keeps running; ERROR_AND_DISABLE (the default) logs a severe error and disables the plugin. |
onMismatch(Consumer<MatchResult>) |
Optional hook called before the action executes, e.g. to log your own localized warning. With WARN_AND_CONTINUE the matcher then skips its own warning, so the admin sees one line. If the hook throws, the matcher logs that as a warning, logs its own mismatch line and still applies the action. |
build() produces a matcher. Call check() if you only need the MatchResult and will handle everything yourself, or enforce() to apply the configured policy automatically.
import net.kroet.turtlelib.helper.ServerMatcher;
public final class MyPlugin extends JavaPlugin {
private ServerMatcher matcher;
@Override
public void onEnable() {
matcher = ServerMatcher.builder(this)
.allowMinorSeries("26.3") // 26.3, 26.3.1, ...
.allowRange("1.20.5", "1.21.10") // optional ranges
.allowVersion("1.20.4") // optional singles
.incompatibleAction(ServerMatcher.IncompatibleAction.WARN_AND_CONTINUE)
.build();
// enforce() already logs the mismatch; use the result for extra handling
ServerMatcher.MatchResult result = matcher.enforce();
if (!isEnabled()) {
return; // ERROR_AND_DISABLE has already disabled the plugin
}
if (!result.supported()) {
// e.g. remember it for an admin join notice
}
}
}- If you disable the plugin on mismatch, remember Paper will log the disable event automatically—no need to spam the console twice.
- A matcher with no versions, ranges, or series treats every Paper server as supported.
- Without an
onMismatchhook,enforce()logs the mismatch itself (prefixed[ServerMatcher]), so don't logresult.message()again. With a hook, your hook is the warning; log it through one channel only (e.g.MessageService#log), not both the console sender and the logger.ERROR_AND_DISABLEalways logs its severe line, since it also disables the plugin. - Keep the allow list close to your release process (e.g., load from config or constants) so updates only require changing one place.
- Uses VersionComparator for range checks; exact versions and series compare as text.
- Pair
onMismatchwith MessageService to log the mismatch warning in the server's language, as Timberella and UnderwaterTrees do.