MCME Wiki

MCME-Warps is the network's warp system. Players teleport to named places with /warp <name>, staff keep a set of public landmarks, and players keep their own private warps. A warp records the server and world it points at, so /warp can move a player to another backend server first. The plugin replaced the third-party MyWarp plugin and stores warps as YAML files, not in a database. This page describes 1.0.7, the latest release, from the MCME/MCME-Warps repository.

At a glance

Repository MCME/MCME-Warps (public, GPL-3.0)
Release branch master (development holds work in progress)
Version described 1.0.7 (tag v1.0.7; master adds only CI changes on top)
Platform One jar, two plugins: MCME-Warps-Velocity on the proxy (velocity-api 3.4.0) and MCME-Warps-Paper on each backend (api-version: 26.1.2, compiled against paper-api 26.2)
Build Gradle (wrapper included) with the Shadow plugin, JDK 25
Depends on Paper half: soft-depends on Dynmap; gets Guava and configurate-yaml through plugin.yml libraries. Velocity half: no plugin dependencies

How the code is organised

The guiding rule is the proxy decides, the backend acts. The Velocity half owns every warp, the config, all commands and permissions, and teleport routing. The Paper half executes teleports and draws Dynmap markers; it holds no state of its own.

src/main/java/com/mcmiddleearth/warps/
├── core/        shared by both halves (must not import Velocity or Bukkit classes)
│   ├── BaseWarp, SimpleLocation, WarpIcon, Utils, WarpLoader, SafeEnumSerializer
│   ├── Channels                 the three plugin-message channel names
│   └── messageprotocols/        the wire protocol (MessageFrame and the message classes)
├── velocity/    the proxy plugin
│   ├── WarpVelocity             @Plugin entry point: registers channels, loads config and warps, builds the commands
│   ├── Permission               every permission node, as an enum
│   ├── commands/                one class per Brigadier command, plus helpers/
│   ├── config/                  Config record + ConfigManager
│   ├── listener/MessageListener backend -> proxy messages
│   └── warps/                   the store: Warp, WarpManager, WarpStore, WarpFileIo, ConfigurateWarpIo, WarpPaths, ...
└── paper/       the backend plugin
    ├── WarpPaper                JavaPlugin entry point
    ├── WarpWatcher              watches the warps folder and updates map markers
    ├── DynmapAPI, MapAPI, Layer, LayerParser   Dynmap markers and layer config
    └── listener/MessageListener proxy -> backend messages

Key ideas:

Building and testing

./gradlew build       # tests + the fat jar
./gradlew shadowJar   # jar only -> build/libs/MCME-Warps-<version>.jar
./gradlew test        # tests only

CI (.github/workflows/build.yml) builds and tests every push and pull request with JDK 25 and keeps the jar as a workflow artifact named MCME-Warps-<version>-<DEV|SNAPSHOT|RELEASE>-<commit>. A v* tag must match the version in build.gradle and sit on the release branch (a pre-release tag such as v1.1.0-rc1 may also come from development); it then creates a GitHub release with the jar and its SHA-256. MCME-Warps does not publish to the Maven repository.

Configuration

Proxy: plugins/mcme-warps-velocity/config.yml. Copied from default-velocity-config.yml on first start and read through Configurate into the Config record.

Key Default Meaning
warp-name-max-length 64 Longest allowed warp name (required)
private-warp-limits.default-limit 2 Private warps a player may keep (required)
private-warp-limits.configured empty (examples commented out) Map of <key>: <limit>. A player with mcmewarps.limits.<key> gets that limit; the highest matching one wins (required, may be empty)
layer-keys [major] Layer names /wmanage setLayer accepts. Must match the custom layers in the backend config
sql.user, sql.password, sql.db-name, sql.ip, sql.port commented out Legacy one-time importer from an old MyWarp database. Used only when the warps folder does not exist yet and every value is set; otherwise ignored

Backend: plugins/MCME-Warps-Paper/config.yml.

Key Default Meaning
debug false Extra log lines
layers.default.label / .min-zoom / .priority "Other warps", 2, 9 The Dynmap marker set for warps without a custom layer
layers.custom.<name>.label / .min-zoom / .priority major: "Major warps", -1, 8 Extra marker sets. min-zoom hides the layer below that zoom (-1: always shown); a higher priority sorts lower in the layer list

Run /wmanage reload (or reload the proxy) after changing the proxy config.

Commands and permissions

All commands are registered by the Velocity half with Brigadier. Subcommand names are case-sensitive (setPublic, not setpublic). The Paper half registers no commands.

Command Aliases What it does Permission
/warp <name> /to Teleport to a warp, switching server if needed mcmewarps.cmd.warp
/warp random /to random Teleport to a random public warp on a fixed set of servers named in RandomCommand mcmewarps.cmd.random
/localwarp <name> /lwarp Go to a warp's coordinates in your current world, without changing server or world mcmewarps.cmd.local-warp
/warpmanager create <name> /wmanage Create a public warp where you stand mcmewarps.cmd.create-public
/wmanage pcreate <name> Create a private warp where you stand (checks the private-warp limit) mcmewarps.cmd.create-private
/wmanage move <warp> Move a warp to where you stand mcmewarps.cmd.move
/wmanage rename <warp> <new> Rename a warp mcmewarps.cmd.rename
/wmanage delete <warp> Delete a warp mcmewarps.cmd.delete
/wmanage setPublic <warp> Make a private warp public mcmewarps.cmd.set-public
/wmanage setPrivate <warp> Make a public warp private mcmewarps.cmd.set-private
/wmanage setWelcome <warp> <message> Arrival message in MiniMessage; default clears it mcmewarps.cmd.welcome-message
/wmanage setIcon <warp> <icon> Map icon: DEFAULT, WIP, ON_HOLD, NOT_STARTED, PIRATE mcmewarps.cmd.set-icon
/wmanage setLayer <warp> <layer> Map layer, one of layer-keys mcmewarps.cmd.set-layer
/wmanage members add\|remove <warp> <player> Manage who may use a private warp (player must be online) mcmewarps.cmd.manage-members
/wmanage list [filters] [page] List warps; filters -v visibility, -c creator, -n name, -s server, -w world, -o order mcmewarps.cmd.list
/wmanage plist [filters] [page] Your private warps and the ones you are a member of mcmewarps.cmd.list
/wmanage assets [filters] [page] Your private warps on your current server mcmewarps.cmd.list
/wmanage reload Write visit counts, reload the config and re-read all warps mcmewarps.cmd.reload

The edit subcommands (delete, rename, move, members, setWelcome) only show for a player who can modify at least one warp.

These permissions are checked on the proxy, so they come from the proxy's permission plugin; there are no built-in defaults.

Permission Grants
mcmewarps.cmd.* nodes above The matching command
mcmewarps.world-access.<world> Teleporting to warps in that world. Needed for every world a player may warp into
mcmewarps.override.use Using any warp, ignoring world access, ownership and membership
mcmewarps.override.modify Editing, moving and deleting any warp, public ones included. Without it nobody can edit an existing public warp
mcmewarps.limits.ignore.private No private-warp limit
mcmewarps.limits.<key> The limit configured under private-warp-limits.configured.<key>

The warps manual explains the commands for players and staff.

APIs and extension points

MCME-Warps has no Java API for other plugins. Its extension points are inside the repository:

How it talks to other plugins and systems

The two halves talk over three plugin-message channels (core/Channels.java). Every message is a MessageFrame: byte 0 is the protocol version, byte 1 a stable opcode, then the body. A receiver on another protocol version rejects the whole message and logs that both jars need the same version, so the proxy and the backends must always run the same MCME-Warps version.

Channel Proxy to backend Backend to proxy
mcme:warp TeleportMessage (SAME_SERVER, DIFF_SERVER, LOCAL_WARP) TeleportResult (SUCCESS)
mcme:player-location RequestLocationMessage (CREATE_PUBLIC, CREATE_PRIVATE, MOVE) PlayerLocationMessage (the player's location)
mcme:misc MiscMessage (UPDATE_COMMANDS) none

The proxy registers all three channels and consumes every message on them, so a message sent by a player's client is never passed on to a backend.

sequenceDiagram
    participant P as Player
    participant V as MCME-Warps-Velocity (proxy)
    participant B as MCME-Warps-Paper (target backend)
    P->>V: /warp Rivendell
    V->>V: look up warp, check access
    alt warp is on another server
        V->>P: connect player to the warp's server
    end
    V->>B: mcme:warp TeleportMessage
    B->>P: teleport
    B->>V: TeleportResult
    V->>V: count the visit

Creating or moving a warp is the reverse round trip: the proxy sends RequestLocationMessage, the backend answers with PlayerLocationMessage, and the proxy writes the warp.

Other system How
Dynmap Paper half only, soft dependency. Public warps for that server become markers in marker sets named mcmewarps.markerset.<layer>. Without an enabled Dynmap the plugin logs a warning and runs without markers
MCME-Connect No integration. Older Connect builds registered /warp and /to themselves; Connect 3.0.1 stopped that and 3.1.0 removed its MyWarp bridge, so MCME-Warps owns both commands. See MCME-Connect
Legacy MyWarp database Read once by MyWarpDBConnector when the sql block is set and no warps folder exists. Dormant otherwise

tools/convert_warps.py (Python 3, standard library) is the one-time migration that removed the old zzz-<player>- prefix from private warp names; its README describes it.

Further reading