MCME Wiki

MCME-Connect links MCME's servers into one network. On the Velocity proxy it handles teleports between players on different servers, server switching, restart orchestration, a server watchdog and join/leave messages; on each Paper backend it carries out what the proxy asks (teleports, commands, titles, restarts), syncs player statistics to MySQL and fires an event other plugins use to react to arrivals. The same jar goes on the proxy and on every backend. This page describes 3.1.1, the latest release, from MCME/MCME-Connect.

At a glance

Repository MCME/MCME-Connect (public)
Release branch master (development holds work in progress)
Version described 3.1.1 (tag v3.1.1)
Platform One jar, two plugins: Velocity id mcmeconnect (velocity-api 4.2.0) and Paper plugin MCME-Connect (compiled against paper-api 26.2)
Build Maven, JDK 25, emits Java 21 bytecode
Depends on Proxy: mcme-base. Backend: MCME-Base (hard); PremiumVanish, DiscordSRV, PluginUtils, Multiverse-Core (soft)

BungeeCord and Waterfall support was removed in 3.0.0; the code is Velocity-only.

How the code is organised

Everything lives under com.mcmiddleearth.connect:

Package Side Job
proxy.velocity proxy ConnectVelocityPlugin (entry point, extends mcme-base's AbstractVelocityPlugin), command classes, Velocity event listeners
proxy.core proxy McmeConnect (state and start-up), McmeConnectConfig, RestartScheduler, ServerInformation
proxy.core.handler proxy One handler per feature: CommandHandler, TpHandler, TpaHandler, TpahereHandler, TpposHandler, MvtpHandler, ThemeHandler, ConnectionHandler, RestartHandler, VanishHandler, ChatMessageHandler, TitleHandler, DiscordMessageHandler, LegacyPlayerHandler, RestorestatsHandler, PluginMessageHandler
proxy.core.watchdog proxy ServerWatchdog: pings every server every two minutes and warns staff about servers that seem down
(root) backend ConnectPlugin (entry point), Channel (channel and sub-channel names), Permission (node names, used on both sides), ServerInfoUpdater
listener backend ConnectPluginListener (messages from the proxy), PlayerListener
restart backend /restart, /stop and scheduled restarts
statistics backend Statistics sync to MySQL (StatisticDBConnector, StatisticSnapshot, StatisticListener) and first-join date sync
events backend PlayerConnectEvent
util backend ConnectUtil (the public helpers), Multiverse spawn lookup
log backend The /log debug logger

The proxy's commands are thin: each ConnectCommand does nothing in execute. CommandListener catches the command in Velocity's CommandExecuteEvent and passes it to CommandHandler. If the target is on another server, Connect handles it and the command stops there. If not (for example /tp to a player on your own server), the command is forwarded to the backend, where EssentialsX or vanilla answers it.

Building and testing

mvn clean verify

This runs the tests and builds the shaded jar target/MCME-Connect-<version>-<TYPE>-<commit>.jar. TYPE is RELEASE unless you pass -Dbuild.type=DEV; commit is the short hash, so two builds of one version can be told apart.

CI (.github/workflows/build.yml) rejects version ranges in the pom, then builds and tests every push and pull request and keeps the jar as a workflow artifact. A v* tag must match the pom version and have a ## [X.Y.Z] section in CHANGELOG.md; it then deploys com.mcmiddleearth:MCME-Connect to repo.mcmiddleearth.com and creates the GitHub release "version X.Y.Z for mc 26.2" with the jar, its SHA-256 and the changelog section. A manual run (workflow_dispatch) also deploys to the Maven repository.

Configuration

One config.yml in the plugin folder, from the same file in the jar. Each side reads its own keys. The shipped file holds only proxy keys; the others take the built-in value shown.

Proxy keys

Key Shipped / built-in Meaning
connectDelay 200 (built-in 2000) Milliseconds to wait after a server switch before sending the follow-up message (teleport, spawn, join reason)
serverWatchdog true Ping all servers every two minutes and warn players with mcmeconnect.watchdog about servers that seem down
premiumVanish true (built-in false) Respect PremiumVanish in join/leave messages and player suggestions
disableMVTP a list of server names Servers from which /mvtp, /switch, /theme, /survival and cross-server teleports are refused (bypass: mcmeconnect.ignoreDisabledMVTP)
legacyRedirect.enabled / .from / .to false (built-in true), two server names Move players who join the network on the from server to the to server
restorestatsBasePath unset Base folder for /restorestats; unset or empty turns the feature off
syncGamemode.<server> true for several servers Not read by any code in 3.1.1
themedbuildWorld built-in: a server name The server /theme sends players to
fixedSwitch built-in none List of "<server> <x> <y> <z> <yaw> <pitch>": /switch <server> lands the player at that spot (in the world named like the server); /switch <server> return skips it
scheduledRestarts built-in none List of "all HH:MM" or "<DAY> HH:MM" restart times
database.user / .password / .dbName / .ip / .port built-in none MySQL login used by /restorestats

Backend keys

Key Built-in Meaning
syncStatistic true Load and save player statistics in MySQL so they add up across servers
database.user / .password / .dbName / .ip / .port placeholder values, localhost, 3306 The statistics database
discordChannel empty DiscordSRV game-channel name ConnectUtil.sendDiscord uses when none is given
scheduledRestarts none As on the proxy, for this backend

Other files: the proxy keeps playerServers.yml (each player's last server, used to pick the server they join), and both sides use a restart.nfo marker file: scheduled restarts and /restart expect a start script that starts the server again while the file exists. First-join date sync reads player data from a playerdata folder inside the plugin folder (see the comment in config.yml) and needs PluginUtils.

Commands and permissions

Most checks run on the proxy, which ignores plugin.yml defaults. Grant the nodes in the proxy's permission plugin as well as on the backends.

Proxy commands

Command Aliases What it does Permission
/tp <player> Teleport to a player on another server mcmeconnect.tp + mcmeconnect.world.<their server>
/tp <player> <target> Teleport one player to another across servers mcmeconnect.tp + mcmeconnect.tp.other
/tphere <player> Bring a player from another server mcmeconnect.tphere
/tpa <player>, /tpahere <player> Ask to teleport to a player, or ask them to come to you mcmeconnect.tpa
/tpaccept, /tpdeny, /tpacancel /tpyes, /tpno Answer or cancel a request none (target world access is checked)
/mvtp <server> /switch <server> /mvtp: switch server and go to the world spawn. /switch: switch server (or go to its fixedSwitch spot) mcmeconnect.world.<server>
/<server> One command per registered server; same as /switch <server> mcmeconnect.world.<server>
/theme Switch to the themed-builds server (themedbuildWorld) mcmeconnect.world.<that server>
/survival Switch to the survival server named in CommandHandler mcmeconnect.survival
/reboot <server…>\|proxy\|all Restart those servers, one after another mcmeconnect.reboot
/stop <server…>\|proxy\|all Stop those servers mcmeconnect.reboot (mcmeconnect.stop shows the command)
/restorestats [joinDateOnly\|allStats] Restore your old statistics or first-join date from a backup; off unless restorestatsBasePath is set none

From the proxy console, /reboot restarts the proxy.

Backend commands (declared in plugin.yml)

Command Aliases What it does Permission
/restart /reboot Restart this server. /restart reloadconfig reloads scheduledRestarts; /restart cancel cancels an announced restart. (/reboot reloadconfig and /reboot cancel reach this command through the proxy) mcmeconnect.reboot
/stop [message] /shutdown Stop this server mcmeconnect.stop
/log /logger Connect's debug log logger.admin

Permission nodes

Permission plugin.yml default Grants
mcmeconnect.tp op /tp <player> across servers
mcmeconnect.tp.other op (includes mcmeconnect.tp) /tp <player> <target> across servers
mcmeconnect.tphere op /tphere across servers
mcmeconnect.tpa not declared /tpa, /tpahere
mcmeconnect.survival not declared /survival
mcmeconnect.world.<server> op (parent node) Entering that server by any Connect command or teleport
mcmeconnect.ignoreDisabledMVTP op Using switch and teleport commands on servers in disableMVTP
mcmeconnect.watchdog op Watchdog warnings about servers that seem down
mcmeconnect.reboot not declared /reboot, proxy /stop <servers>, backend /restart
mcmeconnect.restart op Continuing a multi-server /reboot or /stop: the proxy checks it when a backend passes the rest of the list back
mcmeconnect.stop not declared Backend /stop
logger.admin op /log
pv.see, pv.joinvanished PremiumVanish's nodes Read by Connect to decide who sees join/leave messages of vanished players

mcmeconnect.tablist is still declared in plugin.yml but nothing checks it since the tab list was removed in 3.0.3.

APIs and extension points

Other backend plugins can depend on Connect (Maven: com.mcmiddleearth:MCME-Connect, provided, from the Maven repository) and use:

How it talks to other plugins and systems

Both halves use one plugin-message channel, mcme:connect. Every message starts with a UTF string naming the sub-channel, followed by that sub-channel's fields (Guava ByteArrayDataOutput). The proxy accepts mcme:connect messages only from backend servers, never from a player's client.

Sub-channel Direction Carries
tppos both Teleport a player to a server, world and position (x;y;z;yaw;pitch)
message backend → proxy Chat line for a server and recipient, with a delay
title both Title, subtitle and timings for a server and recipient
Connect backend → proxy Move a player to a server (handled by the proxy; nothing in this repository sends it)
restart both Restart or stop the next server in a list; the backend passes the rest back to the proxy
server_info backend → proxy Periodic server status, read by the proxy's ServerInformation
tp proxy → backend Teleport an arriving player to another player
spawn proxy → backend Teleport an arriving player to the world spawn (Multiverse)
command proxy → backend Run a command as an arriving player
join proxy → backend Player name and ConnectReason; the backend fires PlayerConnectEvent
Discord proxy → backend Join/leave line for DiscordSRV
legacy proxy → backend Save statistics, then move the player (the legacy redirect)
gamemode proxy → backend Set a player's game mode (handled, but not sent by the 3.1.1 proxy)

A multi-server /reboot hops: the proxy moves the issuing player to the first server and sends restart with the rest of the list; that backend restarts itself about three seconds later and sends the list back through the player, and the proxy continues only if the player has mcmeconnect.restart.

flowchart LR
    subgraph Proxy
        CV[MCME-Connect proxy plugin]
        MB1[mcme-base]
    end
    subgraph Backend
        CP[MCME-Connect backend plugin]
        MB2[MCME-Base]
        DS[DiscordSRV]
        PV[PremiumVanish]
        MV[Multiverse-Core]
        PU[PluginUtils]
        IN[MCME-Introduction]
        AR[MCME-Architect]
    end
    DB[(MySQL statistics)]
    CV ---|mcme:connect| CP
    CV --> MB1
    CP --> MB2
    CP --> DS
    CP --> PV
    CP --> MV
    CP --> PU
    CP ---|JDBC| DB
    IN -->|PlayerConnectEvent and ConnectUtil| CP
    AR -->|PlayerConnectEvent| CP
Other system How
mcme-base Required on both sides: the Velocity plugin base class, players, server info, messages and YAML config
PluginUtils Optional on backends; only first-join date sync uses it
MySQL Backend statistics (syncStatistic) and proxy /restorestats, over JDBC with the shaded mysql-connector-j
DiscordSRV Join/leave lines and ConnectUtil.sendDiscord go through DiscordSRV's API; Connect only sends, it never reads Discord
PremiumVanish Vanish state for join/leave messages and suggestions
Multiverse-Core World spawns for /mvtp (Multiverse 5 package names)
MCME-Introduction Listens to PlayerConnectEvent and broadcasts its "just joined" line with ConnectUtil.sendMessage
MCME-Architect Listens to PlayerConnectEvent for its resource-pack handling
TheGaffer Uses no Connect API; it only checks whether Connect is loaded
MCME-Warps No integration. 3.0.1 stopped taking /warp and /to from MCME-Warps, and 3.1.0 removed the old MyWarp bridge

When a backend kicks a player (other than for idling or an unsupported client), the proxy tries to redirect them to a fallback server; the server names are hard-coded in ConnectionHandler.handleKick.

Further reading