Skip to content

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.

Why Use It? 🎯

  • Match explicit Minecraft versions (1.21.1, 1.21.10, etc.).
  • Define inclusive ranges (e.g., 1.20.5 through 1.21.10).
  • Allow a whole major.minor series (e.g., 26.3 accepts 26.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.

Highlights ✨

  • Fluent builder that mixes ranges + singles with optional open-ended bounds.
  • Built-in MatchResult summary for logging and telemetry.
  • Automatic enforcement mode that logs + disables on unsupported servers when configured.

Limitations ⚠️

  • Minecraft version only, on Paper: it reads Bukkit.getMinecraftVersion(), a Paper method. A server without it, such as Spigot, counts as unsupported (Minecraft version unknown) 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 match 26.3.0.
  • Ranges are inclusive and use VersionComparator, with its limits: a maximum of 26.3 rejects 26.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 as 0 (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 exactly 26. Prereleases belong to their series (26.3-pre1 and 26.3-rc1 are in 26.3, unlike in a range), and snapshots (26w14a) never match a series.
  • Silently ignored: a blank allowVersion or allowMinorSeries, and incompatibleAction(null), which keeps the default.
  • ERROR_AND_DISABLE disables right away, inside enforce(), while onEnable() is still running: your onDisable() runs first, and the code after enforce() still runs, so return right after it (see the example).
  • builder(...) needs a JavaPlugin, and its console lines are in English.

Quick Start 🚀

  1. Build a matcher inside onEnable() using explicit versions, ranges, and/or minor series.
  2. Decide how to react via incompatibleAction(...) (warn or disable) and optional mismatch consumer.
  3. Call enforce() during startup; use the returned MatchResult for custom messaging.

References 📚

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).

Builder Reference 🧱

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.

Examples 🧪

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
        }
    }
}

Tips & Notes 💡

  • 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 onMismatch hook, enforce() logs the mismatch itself (prefixed [ServerMatcher]), so don't log result.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_DISABLE always 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.

Relationships to Other Helpers 🔗

  • Uses VersionComparator for range checks; exact versions and series compare as text.
  • Pair onMismatch with MessageService to log the mismatch warning in the server's language, as Timberella and UnderwaterTrees do.

Clone this wiki locally