Repository navigation
Ranked PvP Arena
One permanent map. Elo, an LT/HT ladder, kits, and an optional schematic reset.
Ships off. Command: /pvp. File: pvp.yml.
This is not instanced FFA. FFA copies a map and throws it away. Here the rating carries over; the blocks stay.
Three things are deliberately left to the plugins that already do them.
- Combat tagging. The arena never tags anyone. Whatever combat plugin the server runs stays in charge of tagging, logout punishment and command blocking during a fight.
- Inventory separation. The arena does not snapshot or restore a survival inventory. Give it its own world and let Multiverse-Inventories, or whatever else you already use, keep the two apart. The arena only clears what it handed out when a player leaves.
-
Nametags. The arena publishes
%pvp_rank%and the rest as PlaceholderAPI placeholders. TAB keeps drawing the nametag from them.
Give yourself ultimatedonutsmp2.admin.pvp and work through this in the world the arena lives in.
/pvp create Arena
/pvp setspawn
/pvp setlobby
/pvp wand
/pvp setboundary
/pvp setspawn is the only step the arena cannot open without. Run it where players should appear.
/pvp setlobby records where /pvp leave, a boundary exit and a reconnect send people; without it
the arena falls back to the server spawn. /pvp setspawn2 marks where the second player in a ranked
1v1 starts; leave it unset and both fighters spawn on the same point.
/pvp wand hands you a golden axe. Left click one corner of the arena, right click the opposite
one, then /pvp setboundary stores them. Anyone who steps outside that box - plus the
ARENA.BOUNDARY_PADDING slack - is pulled out of the fight. Skip the boundary entirely and the
whole arena world counts as inside, which is usually what you want for a dedicated world.
Finally switch it on:
SETTINGS:
ENABLED: trueA player picks a kit when they join and again after every respawn, so a kit has to exist before the arena will let anyone in.
/pvp kit create warrior
That opens the editor. The top four rows are the player's inventory - the first row is the hotbar - the four slots at the bottom left are boots, leggings, chestplate and helmet in that order, and the slot after the label is the offhand. Put the real items in. Enchantments, custom names, lore, potion types, stack sizes and items from other plugins all survive, because what gets stored is the item itself rather than a description of it. Closing the menu saves.
The rest of a kit is set from the command line:
/pvp kit icon warrior NETHERITE_SWORD
/pvp kit display warrior &cWarrior
/pvp kit permission warrior ultimatedonutsmp2.pvp.kit.warrior
/pvp kit slot warrior 11
A kit with no permission is open to everyone. A kit with no slot is placed automatically, centred in
the menu alongside the others. The bottom right slot is the leave button, so a kit pointed there is
placed automatically instead. /pvp kit list shows what exists and /pvp kit delete <name>
removes one.
Every kill moves two numbers. Elo decides the rank, and XP decides the level; they are independent on purpose, so a long-serving player can be highly levelled and still rank badly.
ELO:
GAIN_PER_KILL: 25
LOSS_PER_DEATH: 20
LEVELS:
XP_PER_KILL: 50
BASE_XP: 100
XP_INCREASE_PER_LEVEL: 50Ranks are whatever you define. The bundled ladder is the usual LT5 to HT1, but the ids, the names and the Elo each one costs are all yours:
RANKS:
HT5:
DISPLAY: '&eHT5'
ELO: 600A player holds the highest rank they still meet the Elo for, checked after every kill, so ranks go down as well as up with no separate demotion setting to keep in sync.
Levels come off a straight line: level 2 costs BASE_XP, and every level after that costs one more
XP_INCREASE_PER_LEVEL than the one before it. With the defaults that is 100, 150, 200 and so on.
Rank and level changes can be announced to the whole server:
BROADCASTS:
LEVEL_UP:
GLOBAL: true
MESSAGE: '&8[&cPVP&8] &f%player_name% &7has reached PvP Level &c%pvp_level%&7!'Alongside the open arena there is a ranked queue. /pvp queue opens a menu, the player picks the kit
they want to fight with, and confirming puts them in line. As soon as somebody else is waiting for
the same kit the two are paired, dropped on ARENA.SPAWN and ARENA.SPAWN_2, handed the kit, and
held for a short countdown during which neither can be hurt.
Only the same kit pairs. Both fighters use one loadout, so crossing kits would hand whoever waited the gear the other player picked. Within a kit, pairing is by wait time rather than by rating: on a survival server the queue is rarely more than a handful of people, and holding a high rated player back to look for a closer opponent mostly means nobody gets a fight at all.
The queue and the open arena are mutually exclusive. /pvp refuses while you are queued, /pvp queue
refuses while you are in the arena, and /pvp assign refuses to pull somebody out of a fight they
are already in.
The match ends when somebody dies, disconnects, leaves the arena boundary, or MATCH.MAX_DURATION
runs out, which is a draw. The winner gains MATCH.ELO_WIN, the loser drops MATCH.ELO_LOSS, and
both are sent back to the lobby. Ranked deaths never trigger the open arena's per-kill rewards or its
respawn countdown, so a match scores itself once and only once.
MATCH:
ENABLED: true
COUNTDOWN_SECONDS: 5
MAX_DURATION: '5m'
ELO_WIN: 20
ELO_LOSS: 15Four menus cover the ranked side.
/pvp queue is the queue itself: the available kits in the middle, a confirm button on the right, a
leave button on the left. The kit is chosen before queueing rather than after being paired, so two
matched players arrive already agreed on the loadout.
/pvp leaderboard shows one icon per board, with its ranking in the icon's lore. Elo, level, kills,
deaths, best streak and arena joins each get their own, and the icon materials and the row format are
config. Clicking an icon refreshes it.
/pvp history [player] lists past matches newest first, one item each. The lore carries the date,
how long the match ran, who won, and both fighters' hits, crystals and Elo change. Those numbers come
from the stored match row rather than from the players' current totals, so an old entry still reads
correctly long after the ladder has moved on.
/pvp assign is the tester's menu. Click the two player slots to cycle through everyone online,
click the middle slot to pick the kit, then confirm to start the match without either player having
queued. /pvp assign <player> <player> [kit] does the same thing from the command line, which is
what you want when running the same fixture repeatedly. Both need ultimatedonutsmp2.admin.pvp.
Hits and crystals are counted separately during a match. A crystal explosion names the crystal as the damager rather than whoever set it off, so in a ranked match it is credited to the opponent, which is exact because a match only ever has two people in it.
The bundled Discord bot example
reads the ranked tables and adds /mystats, /tier stats, /tier leaderboard, /sync and
/unsync, plus a result posted into a channel after every ranked match showing the winner, the
duration, and both fighters' rank, Elo change, hits, crystals and final health.
Linking works from the game outward. A player runs /pvp sync, the plugin gives them a short
one-time code, and they hand that code to the bot with /sync <code> on Discord. The bot verifies
the code and stores the link on its own side, so the plugin never learns anybody's Discord id and
the bot never needs to write to the server database.
SYNC:
ENABLED: true
CODE_LENGTH: 6
EXPIRES: '10m'Codes are drawn from an alphabet with no characters that read as each other, since a player has to copy one out of chat by eye. Asking for another replaces the one before it, so a code somebody read over a shoulder stops working as soon as its owner asks again.
Killing the same player over and over stops paying:
ANTI_KILL_FARMING:
ENABLED: true
MAX_REWARDED_KILLS: 3
COOLDOWN: '5m'
REDUCED_ELO: 0
REDUCED_XP: 0The counter is per killer and victim pair and forgets a victim once the cooldown passes without another kill. Unrewarded kills still count toward K/D and the streak - they happened - they simply stop paying Elo and XP, and by default they stop costing the victim Elo too.
While a player is in the arena the sidebar comes from pvp.yml instead of scoreboard.yml. It
takes any PlaceholderAPI placeholder, including this feature's own.
SCOREBOARD:
ENABLED: true
TITLE:
- '&c&lPVP ARENA'
LINES:
- '&fRANK: %pvp_rank%'
- '&fLEVEL: &c%pvp_level%'
- '&fK/D: &c%pvp_kills%&7/&c%pvp_deaths%'
- '&fARENA RESET'
- '&c%pvp_arena_reset%'
RESET_FORMAT: '{d}D:{h}H:{m}M:{s}S'RESET_FORMAT takes {d} {h} {m} {s} padded to two digits and {D} {H} {M} {S} unpadded.
The arena can paste a schematic back over itself on a timer instead of regenerating the world.
RESET:
ENABLED: true
INTERVAL: '24h'
WARNING_SECONDS: 30
EVACUATE: true
SCHEMATIC: 'arena'
COMMANDS:
- '//schematic load {schematic}'
- '//paste -o -a'
PASTE_DELAY_SECONDS: 5Save the arena as a schematic with WorldEdit first, then point SCHEMATIC at it - the name only,
no file extension. /pvp schematic load <name> sets it from in game, and /pvp schematic location
records a paste position for configs that want one.
The reset runs the commands from console, in order, waiting PASTE_DELAY_SECONDS between each. That
gap matters: a large schematic is still loading when an immediate paste would fire. Because the work
is done through commands rather than a compiled dependency, the same two lines drive WorldEdit and
FastAsyncWorldEdit, and FAWE is worth installing for a big arena - it is far faster and much easier
on the tick.
INTERVAL accepts 1d10h15m, 24h, 30m, 90s and combinations of those. /pvp reset runs one
immediately.
Survival commands are switched off inside the arena.
BLOCKED_COMMANDS:
ENABLED: true
COMMANDS:
- 'shop'
- 'sell'
- 'ah'
- 'ec'
- 'enderchest'
- 'orders'
BLOCK_ENDER_CHEST_BLOCK: trueA blocked entry covers its subcommands, so shop also blocks /shop sell, and a plugin-qualified
form like /otherplugin:shop is caught too. BLOCK_ENDER_CHEST_BLOCK closes the other door into
the ender chest, the block itself. Holders of ultimatedonutsmp2.admin.pvp are exempt from all of
it.
| Command | What it does |
|---|---|
/pvp |
Join the arena and pick a kit |
/pvp leave |
Leave and return to the lobby |
/pvp kit |
Reopen the kit menu |
/pvp stats [player] |
Elo, rank, level, XP, K/D and streaks |
/pvp top [amount] |
The Elo ladder, offline players included |
/pvp queue |
Open the ranked 1v1 queue |
/pvp queue leave |
Leave the queue |
/pvp leaderboard |
Open the leaderboards |
/pvp history [player] |
Browse ranked match history |
/pvp sync |
Get a one-time code to link a Discord account |
See Config-pvp.yml for every option, and
Placeholders & Integrations for the %pvp_*% catalog.
UltimateDonutSMP V2 1.0 · Paper / Purpur / Pufferfish / Spigot / Folia · Minecraft 26.1.2–26.2 · Java clients 1.21.6+
- Economy & Marketplaces
- Crates & Spawners
- Duels & Instanced FFA
- Ranked PvP Arena
- Cuboids & Portals
- Staff & Security
Core
Menus & display
Economy
Progression
PvP
Staff