DuelForge 2.1.1
A duel plugin for Paper 26.3 with:
- Temporary arena worlds built from a pre-selected area, created through Multiverse-Core
(
/mvcompatible, hidden from normal world lists, deleted again after the duel) — or LIVE: play the duel directly in the real world, with the blocks players changed restored afterwards. - Team duels — 1v1, 2v2, 3v3, 4v4 and (BedWars only) the multi-team shapes 2x4 (two teams of four) and 4x4 (four teams of four), with one spawn and one bed per team.
- Random duels —
/duel random(or the menu button) puts you in a queue where waiting players are matched with each other and the kit and map are picked for the whole group. - BedWars with per-team beds, respawns, iron/gold/emerald generators and NPC item shops
(
shop.ymlcatalogue, click-to-buy for iron, gold and emerald). - Auto-discovered template maps — every world folder named
duelsPaperSpigot-*(configurable) becomes a ready arena by itself;/duelarena scanfinds them on demand. - World settings screen per gamemode —
/duelarena menuis a clickable screen to switch each arena between regular and BedWars, set its content mode, generators, shop and team shapes. - Custom kits with a visual editor — items, armour, offhand, potion effects, health, hunger, flight, natural regeneration, cooldowns and per-kit permissions.
- Multiple maps per kit, weighted random arena picking and per-arena kit whitelists.
- Ranking by wins/losses/streaks and optional Elo for ranked duels, leaderboard menu +
/duelrank top. - Duel requests with clickable accept/deny, a match queue, spectators, countdown, anti-cheat protection while a duel runs and full inventory/XP/effect restore afterwards.
- Menus: opponent picker, kit picker, arena picker, ranked toggle, team shape, random duel, statistics, leaderboard and the admin world settings screen.
Requirements
| Server | Paper 26.3 (tested against build 26.3-169) |
| Java | 25 (Paper 26.3 requires it; the plugin itself is compiled for Java 21 bytecode) |
| Optional | Multiverse-Core 5.8.1+ for /mv managed arena worlds (without it the plugin falls back to plain Bukkit world creation) |
Build
mvn package # produces target/DuelForge-2.1.1.jar
The build compiles against io.papermc.paper:paper-api:26.3.build.169-beta and
org.mvplugins.multiverse.core:multiverse-core:5.8.1 — change the paper.version /
multiverse.version properties in pom.xml if you target another build.
Optionally validate the shipped YAML with the same parser Bukkit uses:
java -cp ~/.m2/repository/org/yaml/snakeyaml/2.2/snakeyaml-2.2.jar \
tools/YamlCheck.java src/main/resources/*.yml
Install
- Drop
DuelForge-2.1.1.jar(and optionallymultiverse-core-5.8.1.jar) intoplugins/. - Start the server once —
plugins/DuelForge/{config.yml,messages.yml,kits.yml,shop.yml}are created. Any world folder namedduelsPaperSpigot-*is registered as an arena automatically.
Quick start
1. Build the arena
Three ways, easiest first.
Template worlds — one command. Drop a ready-made map into the server folder as a world whose name
starts with arenas.template-prefix (default duelsPaperSpigot-, e.g. duelsPaperSpigot-1,
duelsPaperSpigot-2, …). DuelForge loads/imports such a world itself and — because a prefix is a
wildcard — one arena entry accepts any matching world, so you add maps by dropping in folders:
/duelarena quick classic duelsPaperSpigot- # whole-world clone arena, spawns + beds auto-set
/duelarena quick bedfight duelsPaperSpigot- bedwars # BedWars variant
(Pass an exact name such as duelsPaperSpigot-1 to pin one specific map. In a normal world
/duelarena quick <name> instead cuts a arenas.default-box-radius cube around you.)
The region becomes the whole world (arenas.world-radius, which also becomes the world border),
spawn 1 is the world spawn, spawn 2 a safe spot alongside it, spectator 8 blocks above, and for
bedwars two beds are placed two blocks behind the spawns. Review it any time with
/duelarena info classic / /duelarena check classic.
Boxes / whole worlds — also one command.
/duelarena quick classic 40 # cube of radius 40 around you, spawns + beds auto-set
/duelarena box 40 classic # just re-cut the region to a cube around you
/duelarena world classic # make the arena the whole world you are standing in
/duelarena autospawn classic # (re)derive spawn 1/2 + spectator from the region
/duelarena autobeds classic # (re)derive the bed anchors
Fully manual (full control; a dedicated template world such as duel_template is recommended so
the clone only contains arena content):
/mv create duel_template normal # optional, only when using Multiverse
/duelarena create classic # remembers you are editing "classic"
/duelarena wand # left click = position 1, right click = position 2
/duelarena pos1 /duelarena pos2 # alternative: mark your current position
/duelarena region classic # store the two corners as the arena region
/duelarena setspawn 1 classic # stand where player 1 should spawn
/duelarena setspawn 2 classic
/duelarena setspawn spectator classic # optional spectator spot
/duelarena setbed 1 classic # optional: exact bed anchor for team 1
/duelarena save classic
/duelarena check classic # generates the world once and reports the result
/duelarena preview classic # fly through the generated arena, "/duelarena preview stop" to leave
The spawns must be inside the region; the region is what gets cloned/copied into the temporary
world, and it also becomes the world border (world.world-border) so players cannot run away.
Repeat for every map you want — /duelarena list shows all of them, weight controls how often a
map is picked, and kit add <kit> <arena> restricts which kits may be played on a map.
2. Build a kit
/duelkit create sword # copies your current inventory, then opens the editor
/duelkit edit sword # visual editor: slots 0-35 inventory, 36-39 armour, 40 offhand
/duelkit set sword health 20
/duelkit set sword cooldown 60
/duelkit set sword permission duelforge.kit.sword
/duelkit add-effect sword SPEED:1:-1 # type:amplifier:durationTicks (-1 = infinite)
/duelkit info sword
Kits can also be hand-written in kits.yml with a plain items: list — see the comments in that file.
3. Duel
/duel <player> [kit] [arena] [ranked] # send a request (clickable in chat)
/duel accept | deny [player]
/duel queue [kit] [arena] [ranked] # matchmaking against another waiting player
/duel menu # full menu: opponents, kits, arenas, ranked, stats, top
/duel spectate <player>
/duel leave # forfeits the duel (or stops spectating)
4. BedWars duels
An arena created with the bedwars keyword (/duelarena quick bedfight duelsPaperSpigot- bedwars)
or switched later with /duelarena mode bedfight bedwars is played with respawns. Players can also
ask for the mode per request:
/duel <player> bedwars # or `bedwars` as the arena / kit argument, mode keywords win
Rules (all tunable under bedwars: in config.yml):
- Every team gets
bedwars.livesrespawns while its bed stands;respawn-delayseconds after a death they reappear at their own spawn (with the kit again whenrespawn-with-kit) and getrespawn-invulnerabilityseconds of protection. - Breaking the enemy bed removes all their remaining respawns — they are on their last life. Breaking your own bed is cancelled.
- Building and breaking are allowed inside the arena while the duel runs (
allow-block-place,allow-block-break) so islands can be fortified and beds reached. - Beds are placed into the temporary world automatically at the arena’s bed anchors and cleaned up
with the world.
/duelarena autobeds <arena>derives the anchors from the spawns (two blocks behind, i.e. behind the player like in BedWars) and/duelarena setbed 1\|2 <arena>pins them to exactly where you stand and look.bedwars.place-beds: falsekeeps hand-built beds from the map. - The last team standing wins; deaths after the bed is broken end the duel like a normal duel.
/duelarena check <arena> reports the beds it placed in the generated world (4 bed(s), 8/8 bed blocks verified), so you can confirm a map works without starting a duel.
5. Team duels and the random queue
A duel is a set of teams. Team shapes are written 2v2, 3v3, 4v4, or AxB for A teams of
B players:
| Shape | Teams | Players | Modes |
|---|---|---|---|
1v1 |
2 | 2 | regular + BedWars |
2v2 |
2 | 4 | regular + BedWars |
3v3 |
2 | 6 | regular + BedWars |
4v4 (= 2x4) |
2 | 8 | regular + BedWars |
4x4 |
4 | 16 | BedWars only |
2x4 and 4v4 are the same two teams of four, so the spellings share one queue. Every team needs
its own spawn, and in BedWars its own bed — /duelarena autospawn derives up to four of them, and
the shape you queue for picks the teams automatically:
/duel queue 2v2 bedwars # wait for four players, teams of two
/duel queue 4x4 bedwars # BedWars-only four teams of four (16 players)
/duel random 3v3 # random queue: matched with anyone waiting
/duel random # random 1v1
Which shapes are allowed is configurable (teams.formats, teams.bedwars-formats) and per arena
with /duelarena teams <arena> 2v2 3v3 4x4. The menu (/duel menu) has a team-shape button and a
random-duel button.
6. Shops and resource generators (BedWars)
Every BedWars island gets a shop villager and iron + gold generators; the middle of the map also produces iron, gold and emeralds. Right click the villager to open the shop — categories, prices and items come from shop.yml and purchases cost the iron / gold / emerald in your inventory:
/duelarena shop <arena> on|off|default # per arena switch
/duelarena generators <arena> on|off|default
Timings and the safety cap live under bedwars.generators in config.yml
(iron-interval, gold-interval, emerald-interval, max-nearby-items, …).
7. Using a whole world as it is (LIVE)
Each arena can pick how its world is produced — the global world.content-mode or a per-map
override (/duelarena content <arena> CLONE|COPY|LIVE|DEFAULT):
CLONE— duplicate the whole build world through Multiverse.COPY— empty world plus just the selected region.LIVE— no world is created at all: the duel runs in the real world at the arena’s coordinates. Players still build and break inside the BedWars arena, and every block they change is recorded and put back when the duel ends (world.live.restore-changes), so a pre-built map is reusable. Building outside the arena region is still blocked.
8. The world settings screen
/duelarena menu (aliases /da worlds, /da settings) opens a clickable screen listing every
arena. Click one to configure it per gamemode:
- regular / BedWars duel mode,
- arena mode (region or whole world), content mode (default / clone / copy / live),
- generators and shop on/off/default,
- the allowed team shapes,
- buttons that re-derive the team spawns, the bed anchors or everything at once,
- enable/disable, save and back.
9. Template maps are discovered automatically
Any world folder whose name starts with arenas.template-prefix (duelsPaperSpigot- by default) is
registered as a whole-world BedWars arena on startup — drop a map folder into the server and it works.
The spawns, beds and playable region are derived from the map the first time it is generated.
/duelarena scan does the same on demand and is safe to run repeatedly.
Console output after this was verified on a real server
[DuelForge] Enabling DuelForge v1.0.0
[DuelForge] Loaded 3 kits and 1 arenas.
[DuelForge] World mode: MULTIVERSE / content mode: CLONE
[DuelForge] Ranking: WINS
DuelForge » Generating arena <aqua>Test Arena...
[DuelForge] [debug] Copied 867 blocks into duelforge_test_1
[DuelForge] [debug] region copy verification: 8/8 sampled blocks match
DuelForge » Arena <aqua>Test Arena generated successfully (duelforge_test_1, 867 blocks copied, spawn duelforge_test_1 3/70/8)
[DuelForge] [debug] Deleted temporary world duelforge_test_1 through Multiverse.
Commands
| Command | Permission | Description |
|---|---|---|
/duel [menu] |
duelforge.duel |
Open the duel menu (defaults to it when run without arguments) |
/duel <player> [kit] [arena] [ranked] |
duelforge.duel |
Send a duel request |
/duel accept|deny [player] |
duelforge.duel |
Answer a request |
/duel queue [kit] [arena] [2v2|3v3|4v4|4x4] [ranked] [bedwars] |
duelforge.duel |
Join the match queue for a team shape |
/duel random [1v1|2v2|3v3|4v4|4x4] [ranked] [bedwars] |
duelforge.duel |
Random queue: matched with anyone, random kit and map |
/duel spectate <player> |
duelforge.spectate |
Watch a duel (spectator mode) |
/duel leave |
duelforge.duel |
Forfeit / stop spectating / leave the queue |
/duel stats [player] |
duelforge.duel |
Statistics menu |
/duel top [page] |
duelforge.duel |
Leaderboard |
/duel stop <player> |
duelforge.admin.duel |
Abort a running duel |
/duel reload |
duelforge.admin.reload |
Reload config, messages, kits and arenas |
/duelkit create|edit|delete|list|info|give|icon|set|add-effect|clear-effects |
duelforge.command.kit |
Kit management |
/duelarena quick <name> [world|prefix] [radius] [bedwars] |
duelforge.admin.arena |
Create a playable arena in one command — whole-world for a template prefix, otherwise a box around you — with spawns (and beds for bedwars) derived automatically |
/duelarena create|pos1|pos2|wand|region|box|world|autospawn|autobeds|setspawn|setbed|mode|save|list|info|enable|disable|delete|kit|tp|weight|icon|check|preview|reload |
duelforge.admin.arena |
Arena management (check/preview generate a world once so you can test a map) |
/duelarena menu|worlds|settings |
duelforge.admin.arena |
Clickable world settings screen per gamemode |
/duelarena scan |
duelforge.admin.arena |
Register one arena per template map found |
/duelarena content <arena> <DEFAULT|CLONE|COPY|LIVE> |
duelforge.admin.arena |
How the arena’s world is produced |
/duelarena teams <arena> [2v2 3v3 4v4 4x4] |
duelforge.admin.arena |
Allowed team shapes (no shapes = all) |
/duelarena generators|shop <arena> [on|off|default] |
duelforge.admin.arena |
Per-arena BedWars extras |
/duelrank top|stats|reset <player|all> |
duelforge.rank (duelforge.admin.rank for reset) |
Ranking |
Aliases: /duels, /df, /da, /arenas, /dk, /kits, /dr, /rank.
Console can use list, info, check, enable/disable, delete, kit, weight, icon, save,
reload and duelrank; anything that needs a location or inventory (region, spawns, preview, kits)
requires a player.
Permissions
| Node | Default | Purpose |
|---|---|---|
duelforge.duel |
true | Use /duel |
duelforge.spectate |
true | Spectate duels |
duelforge.rank |
true | Use /duelrank and the leaderboard |
duelforge.kit.list |
true | List kits |
duelforge.command.kit |
op | Manage kits |
duelforge.admin.arena |
op | Manage arenas |
duelforge.admin.reload |
op | /duel reload |
duelforge.admin.duel |
op | /duel stop |
duelforge.admin.rank |
op | /duelrank reset |
| per-kit | — | Optional node you set with /duelkit set <kit> permission <node> |
How the temporary arena world works
world.content-mode (a per-arena override wins) picks one of three strategies:
CLONE (default, needs Multiverse)
Multiverse-Coreduplicates the arena’s whole build world (CloneWorldOptions), which keeps every block, entity, biome and tile entity exactly as built and is a fast file copy.- Cheap for many arenas only if each arena lives in its own template world — cloning duplicates the entire world folder. Use one template world per map, or switch to COPY.
- Template worlds: a
source-worldthat is not an exact world name is treated as a prefix, soduelsPaperSpigot-picks up any world namedduelsPaperSpigot-1,duelsPaperSpigot-2, … (arenas.template-prefixdecides which worlds/duelarena quickturns into whole-world arenas). Such a world does not have to be imported into Multiverse by hand: DuelForge loads and imports it before the first clone, and it also survives to be reused as aWORLD-mode arena.
COPY
- A completely empty void world is created and only the selected region is pasted into it
(
world.copy.paste-origin, batchedworld.copy.blocks-per-tickper tick, optional biome copy). - Spawns are remapped by the paste offset automatically.
- Ideal when all maps live in one big build world.
LIVE
- Nothing is created, loaded or deleted: the duel runs in the real build world at the arena’s own coordinates, which is what you want for a map that is already perfect in place.
- Players build and break inside the arena region during a BedWars duel; the previous state of every
changed block is recorded and restored when the duel ends (
world.live.restore-changes,world.live.max-recorded-blocks). - Block protection is limited to the arena region instead of the whole world.
CLONE and COPY then apply world.settings: time, weather, difficulty, the game-rules map (modern names
such as advance_time and classic names such as doDaylightCycle both resolve), PvP on, auto-save
off, a world border around the region and the spawn set to spawn 1.
Lifecycle: world.reuse-worlds keeps generated worlds loaded for the next duel (fast replays,
world.max-cached-per-arena), otherwise they are deleted world.delete-delay seconds after the duel
ends. Unused cached worlds are purged after 10 minutes. On shutdown every temporary world is removed.
Without Multiverse the plugin logs a warning and falls back to plain Bukkit world creation (COPY mode
only), and cleans up with Bukkit.unloadWorld + folder deletion.
Configuration highlights
All options documented inline in config.yml. The most useful ones:
duel.request-timeout,countdown,max-duration,freeze-during-countdown,protect-during-countdown,restore-state,keep-inventory-on-death,quit-is-loss,confine-to-arena,post-duel-guard,cooldown,reward-commands.kits.default-kit,kits.respect-kit-permissions,kits.selection-enabled.ranking.enabled,sort-by: WINS|ELO|STREAK,count-casual,elo.start|k-factor|floor.arenas.random-selection,arenas.use-preview-spawn(players wait at the spectator spot during the countdown),arenas.template-prefix(which worlds/duelarena quicktreats as ready-made maps),arenas.world-radius,arenas.default-box-radius.bedwars.*:lives,respawn-delay,respawn-invulnerability,respawn-with-kit,place-beds,allow-block-place,allow-block-break,shop.enabled,generators.*.teams.enabled,teams.formats,teams.bedwars-formats,teams.random-queue.world.live.enabled,world.live.restore-changes,world.live.max-recorded-blocks.arenas.auto-discover.enabled|bedwars|radius.gui.*titles and filler,messages.prefix.
Message texts live in messages.yml and use MiniMessage, e.g.
'<gold>{winner}</gold> <gray>defeated</gray> <gold>{loser}</gold>'. {placeholders} are escaped
before parsing, so a player name can never inject formatting.
Storage
| File | Content |
|---|---|
plugins/DuelForge/config.yml |
settings |
plugins/DuelForge/messages.yml |
all texts |
plugins/DuelForge/kits.yml |
kits (items as Base64 NBT, or the readable items: shorthand) |
plugins/DuelForge/arenas.yml |
arenas: region, team spawns, beds, content/duel mode, generators, shop, formats, weight, icon, kit whitelist |
plugins/DuelForge/shop.yml |
BedWars shop categories, items and prices |
plugins/DuelForge/playerdata/<uuid>.yml |
wins, losses, ranked results, Elo points, streaks |
For developers
- Two events are fired:
net.freebuff.duelforge.event.DuelStartEvent(cancellable, fired right before the players are teleported) andDuelEndEvent(winner, loser,DuelEndReason). Duelalready keeps a list of players per side, so team duels can be added without changing the flow.- Everything is wired in DuelForgePlugin:
ArenaManager,ArenaWorldService(+MultiverseHook),KitManager,DuelManager,RankingManager. - Class layout: arena, kit, duel, rank, gui, command, listener.
Verified on Paper 26.3 build 169 (DuelForge 2.1.1)
- Plugin loads and enables together with Multiverse-Core 5.8.1 without errors or warnings.
- Arena world generation through Multiverse: clone mode, and copy mode (867 blocks copied, 8/8 sampled blocks re-read and matching, spawn coordinates remapped to the paste offset).
- Graceful fallback to Bukkit world creation when Multiverse-Core is absent.
- Template worlds: an arena whose
source-worldis a prefix (duelsPaperSpigot-) clones any matching folder; aduelsPaperSpigot-1world that Multiverse failed to auto-load was loaded, imported and cloned by the plugin itself (duelforge_vfy_1, cloned). /duelarena quickcreated a single-command arena (region, both spawns and the spectator spot derived from the world) for a template prefix in bothnormalandbedwarsvariants.- BedWars:
4 bed(s), 8/8 bed blocks verified— four teams get a bed (red/blue/green/yellow) placed in the generated world and re-read back, with/duelarena autobedsderiving the anchors. - Auto-discovery: three template worlds were registered on startup; a fresh
duelsPaperSpigot-1world was cloned successfully by/duelarena check(spawn 32/87/0). - LIVE content mode:
/duelarena content <arena> LIVEgenerated nothing and used the real world (live (no world created)) while still placing and verifying all eight bed blocks. - Team shapes:
TeamFormatparsing checked directly —2/2v2→ two teams of two,2x4and4v4→ two teams of four,4x4→ four teams of four (BedWars only), garbage → null. - Shop:
shop.ymlloads as 5 categories / 23 items on startup without errors. - Per-arena settings:
/duelarena teams,content,generators,shopround-trip througharenas.ymland are re-read after a restart. - Temp world reuse pool, delayed deletion (Multiverse and Bukkit paths) and shutdown cleanup — no leftover world folders.
/duelkit list|info,/duelarena list|info|check|enable|disable|weight|icon|kit|save,/duelrank topand/duelhelp — including the console paths — with zero missing message keys or exceptions in the log.- Message placeholders, the
items:kit shorthand (the shippedclassickit loads as 7 items), and gamerule resolution (modern + legacy names). - Arena state round-trip: weight/icon/kit whitelist/enabled changes survive a restart and are re-read
from
arenas.yml.
Not verified automatically: the interactive player flows (request/accept, GUI clicks — including the
world settings screen, the shop and team-shape buttons — kit editor, death/respawn restore, the
BedWars life/bed-break cycle, generator item drops and NPC right-clicks during a live duel, team
matchmaking with real players, spectator handling, Elo writes) need a real client. Everything
reachable without one is verified by /duelarena check, /duelarena scan, the console commands and
the startup log.