Voor servers

Fern Server Link

Laat je server zich thuis voelen in Fern: herken Fern-spelers, houd potjes eerlijk en praat met spelers, met een paar kleine JSON-berichten via plugin-kanalen.

Weet wie Fern speelt

Een kleine handshake vertelt je plugin welke spelers Fern gebruiken, alleen als zij dat toestaan.

Eerlijke potjes

Zet specifieke Fern-features uit en vergrendel ze op je server, met een reden die spelers kunnen lezen.

Meldingen

Korte meldingen met een limiet, voor aankondigingen, beloningen of gebeurtenissen in het spel.

Timers op het scherm

Aftellers bovenaan het scherm voor de start van een potje, events en cooldowns.

Deze pagina is alleen in het Engels beschikbaar.

Status: protocol 1, client support in Fern 0.1. A ready-made Paper plugin is planned; until then you can talk to Fern directly with plugin messages (examples below).

How it works

Fern listens on a few plugin-message channels that all start with fern:. Every message is a small UTF-8 JSON object (max 8 KB).

The server always starts the conversation: Fern never announces itself on servers that don't ask.

text
Player joins
   server ──► fern:welcome   {"protocol": 1}
   client ──► fern:hello     {"client": "fern", "version": "0.1.0", ...}   (only if the player allows it)
   server ──► fern:rules / fern:notify / fern:timer   (any time)
Player leaves → everything your server set is undone on the client

Players who don't use Fern simply ignore these channels — sending them is always safe.

Channels

ChannelDirectionWhat it does
fern:welcomeserver → client"This server supports Fern Server Link." Starts the handshake.
fern:helloclient → serverFern's answer: version, mod loader, enabled Fern mods.
fern:rulesserver → clientTurn off and lock Fern mods on your server.
fern:notifyserver → clientShow a notification (toast).
fern:timerserver → clientShow, update or remove a countdown at the top of the screen.
fern:waypointserver → clientPlanned: markers in the world.
fern:presenceserver → clientPlanned: what the player's Discord status says while on your server.

fern:welcome

json
{ "protocol": 1 }

Send it once, shortly after the player joined (for example 1 tick after PlayerJoinEvent, so the client has registered its channels).

fern:hello (from the player)

json
{
  "protocol": 1,
  "client": "fern",
  "version": "0.1.0",
  "loader": "fabric",
  "minecraft": "26.3",
  "modules": ["fps", "zoom", "keystrokes"]
}

Players can turn this off (Features → Server Features → Tell servers I use Fern). If you never receive a hello, treat the player as a normal player.

fern:rules

json
{ "disable": ["zoom", "fullbright"], "reason": "Not allowed in ranked matches" }
  • The listed mods are switched off and locked until the player leaves your server. The player sees the reason when they try to turn one back on.
  • Rules only restrict. You can't turn mods on, change settings or unlock anything.
  • Rules apply even when the player turned *Server Features* off — fair play comes first.
  • Send fern:rules again to lock more mods. Max 64 ids per message; unknown ids are ignored.

fern:notify

json
{ "title": "Welcome to Mossy Network", "body": "Season 3 starts today!" }
  • title max 48 characters, body max 160. Formatting codes (§) are removed.
  • Max 5 notifications per 10 seconds per player; extra ones are dropped. Players can turn notifications off.

fern:timer

json
{ "id": "start", "label": "Game starts in", "seconds": 10, "color": "#4ADE80" }
  • Shows a countdown at the top centre of the screen, e.g. Game starts in 10s.
  • Same id again = update it. "seconds": 0 = remove it. Max 3 timers, max 3600 seconds.
  • color is optional (hex). Players can turn timers off.

Module ids

IdFern modIdFern mod
fpsFPSzoomZoom
pingPingtoggle_sprintToggle Sprint
coordinatesCoordinatestoggle_sneakToggle Sneak
clockClockfullbrightFullbright
keystrokesKeystrokescrosshairCustom Crosshair
cpsCPSarmor_statusArmor Status
potion_effectsPotion EffectsdirectionDirection
memoryMemory

New Fern mods get new ids; unknown ids are always ignored, so your rules keep working.

Example: Paper plugin

java
public final class FernLinkExample extends JavaPlugin implements Listener, PluginMessageListener {
    @Override
    public void onEnable() {
        var messenger = getServer().getMessenger();
        for (String ch : List.of("fern:welcome", "fern:rules", "fern:notify", "fern:timer")) {
            messenger.registerOutgoingPluginChannel(this, ch);
        }
        messenger.registerIncomingPluginChannel(this, "fern:hello", this);
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        // One tick later, so the client has told the server which channels it listens on.
        getServer().getScheduler().runTaskLater(this, () -> send(player, "fern:welcome", "{\"protocol\":1}"), 1L);
    }

    @Override
    public void onPluginMessageReceived(String channel, Player player, byte[] message) {
        // Read and validate the JSON before trusting it — it comes from the player.
        String hello = readString(message);
        getLogger().info(player.getName() + " uses Fern: " + hello);

        send(player, "fern:rules", "{\"disable\":[\"zoom\"],\"reason\":\"No zoom in ranked\"}");
        send(player, "fern:notify", "{\"title\":\"Fern detected\",\"body\":\"Have fun!\"}");
    }

    private void send(Player player, String channel, String json) {
        player.sendPluginMessage(this, channel, writeString(json));
    }

    // Minecraft strings: VarInt length + UTF-8 bytes.
    private static byte[] writeString(String s) {
        byte[] utf8 = s.getBytes(StandardCharsets.UTF_8);
        var out = new ByteArrayOutputStream();
        int len = utf8.length;
        while ((len & ~0x7F) != 0) { out.write((len & 0x7F) | 0x80); len >>>= 7; }
        out.write(len);
        out.writeBytes(utf8);
        return out.toByteArray();
    }

    private static String readString(byte[] data) {
        int len = 0, shift = 0, i = 0, b;
        do { b = data[i++]; len |= (b & 0x7F) << shift; shift += 7; } while ((b & 0x80) != 0 && shift < 35);
        return new String(data, i, Math.min(len, data.length - i), StandardCharsets.UTF_8);
    }
}

Rules for servers

  • Don't trust `fern:hello` for security decisions. Any client can claim to be Fern. Use it for comfort features only, never for anti-cheat or permissions.
  • Use rules for fair play, not to punish Fern players. Fern players should never be at a disadvantage compared to vanilla players.
  • Keep notifications useful and rare; players who find them spammy will turn them off.
  • Respect the Minecraft EULA and Usage Guidelines.

Privacy

fern:hello only contains the Fern version, mod loader, Minecraft version and enabled Fern mod ids — no account data, hardware or files. Players can turn it off. Servers receive nothing from Fern unless they send fern:welcome first.

Changelog

ProtocolFernChanges
10.1welcome, hello, rules, notify, timer