A Paper plugin for the hub server of a Velocity network. It runs a catalog of minigames on a small pool of interchangeable Pterodactyl server slots: players pick a game from a GUI, the plugin allocates a slot, tells it which game to set up through an egg variable, and transfers players as soon as the server accepts connections. Slots swap between minigames on demand, and empty slots are stopped automatically.
- A player runs
/minigameon the hub and a GUI opens with every game category, then the maps for the chosen game, showing which ones are live and how many people are playing. - Clicking a map routes the player:
- already running on a slot → transferred straight there;
- already starting → queued, moved when it's ready;
- otherwise the plugin allocates a slot: an offline slot is preferred; if none is offline, an empty online slot is swapped over (stop → wait until down → start with the new game). If every slot has players, they're asked to try again later.
- To start a slot, the plugin writes the game's archive filename (e.g.
Games_Sumo_Lava.tar.gz) into theMINIGAMEegg variable, then sends the start power action. The startup script on the server extracts that archive (.zipand.tar.gzboth supported) and launches — a fresh copy of the game on every boot (seeexamples/entrypoint.sh). - The hub pings the slot until it accepts connections, then sends every queued player over the proxy's plugin messaging channel. Players wait on the hub in the meantime.
- A slot that has been empty for
idle_shutdown_afterseconds is stopped, freeing it for another game. On hub restart, the plugin recovers which game each slot is running by reading the variable's current value back from the panel.
| Command | Permission | Description |
|---|---|---|
/minigame |
minigamemanager.join (default: everyone) |
Open the minigame picker GUI |
/minigame join <minigame> |
minigamemanager.join |
Join a game directly (same flow as the GUI) |
/minigame start <minigame> |
minigamemanager.admin |
Start a game without joining |
/minigame stop <slot> |
minigamemanager.admin |
Stop a server slot |
/minigame command <slot> <…> |
minigamemanager.admin |
Send a console command to a running slot |
/minigame status |
minigamemanager.admin |
Show each slot's state, players and current game |
/minigame reload |
minigamemanager.admin |
Reload the configuration |
/mg is an alias for /minigame.
All slot servers share one egg. The easiest path is importing the ready-made
egg-paper.json (Admin → Nests → Import Egg): it is the standard Paper egg with the
MINIGAME variable added and an install script that also writes entrypoint.sh to the
server, which the startup command runs. Existing servers must be reinstalled once
after switching to this egg so the install script creates entrypoint.sh (or upload
examples/entrypoint.sh manually).
If you'd rather extend your own egg by hand, add a variable to it:
| Field | Value |
|---|---|
| Environment Variable | MINIGAME (must match minigame_variable) |
| Default Value | any valid archive filename |
| Permissions | User Viewable and User Editable |
| Validation Rules | required|string|regex:/^[\w.\-]+$/ |
The variable must be user editable, otherwise the client API is not allowed to change it, and the validation rules must allow dots/hyphens since the value is a filename. If you use a sub-user API key, it needs the Startup: Update permission on top of the power/command permissions.
Set the egg's startup command to run a script like examples/entrypoint.sh, and upload the
minigame archives to each slot server's /home/container. Each archive contains
everything specific to that game (worlds, plugins/, configs) laid out as it should
appear after extraction; shared files like server.jar can live outside the archives.
Drop the jar in the hub's plugins/ folder and edit plugins/MinigameManager/config.yml:
pterodactyl:
base_url: "https://panel.example.com"
api_key: "ptlc_xxx"
servers: # the slot pool — any slot can host any game
minigame-1: # must match the server name in velocity.toml
identifier: "abc123de" # Pterodactyl server identifier
address: "10.0.0.5:25566" # address the hub can reach for pings
minigames: # the catalog: categories shown first in the GUI
sumo:
display_name: "Sumo"
icon: LAVA_BUCKET
description: "Knock them in!" # optional
maps: # picked after the category (skipped if only one)
sumo_lava: # key used by /minigame join|start, unique overall
archive: "Games_Sumo_Lava.tar.gz"
display_name: "Lava" # optional, shown as "Sumo (Lava)"
icon: MAGMA_BLOCK # optional, defaults to the category iconThe default config ships with the full OGCraft catalog. Adding a new minigame is: upload
the archive to the slot servers, add a map entry under its category, /minigame reload.
- Player transfers use the BungeeCord plugin messaging channel, so
bungee-plugin-message-channel = truemust be set invelocity.toml(it is the default). - Each slot must be defined in
velocity.tomlunder the same name as its entry in this plugin's config. - If joins should only go through the hub, don't grant players
velocity.command.server.
- Pings go directly from the hub to the slots, so
addressmust be reachable from the hub. /minigame commandonly works while the slot is running — an offline container has no console. Game selection for a boot always goes through the egg variable.- A swap only ever targets an empty slot; players are never kicked to make room.
- Hook NPCs or signs up by making them run
minigame(opens the GUI) orminigame join <key>as the player.
./gradlew build
The jar is written to build/libs/. Requires Java 21+.