ResetWorld
A Minecraft server plugin for shared hardcore: when anyone dies, everyone is wiped and the whole map is put back from a template.
I made this for my friends. We wanted to play a hardcore challenge together on a server, and the part nobody wanted to do was the cleanup after each failed attempt. Minecraft has a mode called hardcore, where you get one life. On a server with friends it gets more interesting, because the life can be shared: if one person walks into lava, everyone's run is over. Then someone has to stop the server, delete the world, copy a fresh map back in and clear everybody's inventory and progress. I wrote a plugin, which is a small add-on for the server, that does all of that by itself.
We used it for a Hardcore Shared Health Skyblock challenge that lasted about three days. It ended when all of us went into the End and the ender dragon breathed on the confined spawn platform. The breath hurt everyone at once, and everyone was dead in under half a second. It was ridiculous. Everybody rage-quit straight after.
I wanted it to work on a custom map rather than a random world, so the plugin keeps a clean copy of the map and restores that every time. Think of a board game where, if any player's piece falls off the board, the whole board is cleared and set up again from the box.
When somebody dies in the hardcore world, the server tells everyone who it was and how long the run lasted, and a ten second countdown starts. Everyone still alive turns into a spectator and then gets moved to a small waiting lobby. The plugin deletes the hardcore world and copies the clean one back. Then everybody is dropped at the start with an empty inventory, no experience, no potion effects and no achievements, and the server announces that the next run has started. An op, which is a server admin, can also trigger the whole thing with a command. Anyone who was offline during a reset gets wiped the moment they log in, so nobody comes back with last run's diamonds.
Deleting a world right after the server lets go of it can fail on Windows, because the files stay busy for a moment, so the plugin just tries again a few times. The copying happens in the background so the game doesn't freeze for everyone while a big map moves. And Minecraft has two extra worlds reached through portals, the Nether and the End, so the plugin makes the portals lead to this run's copies and not the lobby's.
It does the job, and it has been used for real, but it is a small plugin. It has no automated tests, it only targets one version of the server software, and it keeps no record of past runs beyond a counter. When it starts it also prints a rainbow greeting in the console, which is the one thing in it that does nothing useful.
What's next. It is finished as far as the challenge went. If I came back to it, I would add a history of past runs, a setting for difficulty, and a way to recover cleanly when a reset fails halfway.
The problem
I built this for friends. We were going to run hardcore challenges on a shared server, and the tedious part is the reset after each failure. Hardcore Minecraft gives you one life, and on a server I wanted that life shared, so a single death ends the run for everyone. Doing that by hand means stopping the server, deleting the world folders, copying a fresh map back and clearing every player's inventory, XP and advancements, every time. I wanted a custom map rather than a random seed, so the plugin keeps a template of it and restores that.
It got used for a Hardcore Shared Health Skyblock challenge that ran for roughly three days. That ended when everyone went into the End and the dragon's breath hit the confined spawn platform, damaging all of us at once. Everyone died in under half a second, and everyone rage-quit afterwards. The plugin ignores a second death during the countdown, so a pile of deaths at once only starts one reset.
How it works
It's a Paper plugin in Java 21, about 690 lines of Java and config. Four classes: ResetWorldPlugin starts everything, HardcoreManager owns the worlds, the run counter and the reset cycle, HardcoreListener handles the game events, and ResetCommand is the /resetworld command, which is op only.
What is Paper?
Paper is a widely used Minecraft server program, a faster fork of Spigot. A plugin is a Java jar you drop into the server's plugins/ folder. It can hook into events such as a player dying, joining or walking through a portal, and it can load, unload and create worlds.
The plugin keeps three worlds, hardcore, hardcore_nether and hardcore_the_end, and treats the server's normal world as the lobby. At startup it refuses to run if the hardcore world has the same name as the lobby, or if there is no template. If the hardcore folder already exists, the current run carries on across server restarts, and the template is only copied when there is nothing there.
Click through one reset below. Pick a step in the diagram or from the buttons, or use Back and Next.
Why does the copying run off the main thread?
The server does all its game logic on one main thread, in ticks of 50 ms, twenty a second. If that thread spends a few seconds copying a big map, every player freezes for those seconds. So the slow disk work goes to a separate thread, and the plugin only comes back to the main thread to load the worlds and move people once the files are in place.
Some details exist because the obvious version would break. Players who were offline during a reset carry the run number in their saved data, and on join a mismatch means they get wiped too. Someone who logged out on the death screen is respawned when they come back. Anyone who joins mid-reset is sent to the lobby. And a wipe clears more than the inventory: the ender chest, the item on the cursor, XP, effects, health and hunger, fire and freeze, the bed spawn, the phantom timer, and every advancement.
The three worlds also have to be built from the template. A singleplayer save keeps its nether and end inside the same folder, in DIM-1 and DIM1, while Paper uses separate world folders, so the plugin splits them on the way in. If you give it separate templates/world_nether and templates/world_the_end folders, those win. If there are none, the nether and end are generated fresh from the overworld's seed.
What are DIM-1 and DIM1, and why skip uid.dat?
In a singleplayer save the overworld sits in the main folder and the nether and end are subfolders called DIM-1 and DIM1. A server wants each one as its own world, so the copy step puts them in hardcore_nether/DIM-1 and hardcore_the_end/DIM1. Each world folder also has a uid.dat holding its unique ID. Copying it every run would give every run the same world ID, so it's left out and the server makes a new one, along with session.lock.
Portals
A hardcore overworld that sent its portals to the lobby's nether would be no good, so portals are rerouted by hand. Going into the nether, X and Z are divided by 8; coming out, they are multiplied by 8. If you stand in a portal at X 800, Z -240 in the hardcore overworld, you arrive near X 100, Z -30 in the hardcore nether, and the game looks for an existing portal within 16 blocks of that spot before it builds a new one. Coming back the other way it looks within 128.
Height is clamped to the world's limits. The end works differently. Going into the end always puts you on a platform at X 100.5, Y 49, Z 0.5, and the plugin rebuilds the 5x5 obsidian square vanilla makes there, with air cleared above it. Leaving the end sends you to your bed if it is in a hardcore world, and to the map spawn if not. The respawn handler does the same if you jump into the end exit portal with no bed set, where vanilla would have sent you to the lobby.
world-name: hardcore countdown-seconds: 10
What didn't work
Windows can keep region files open for a moment after a world is unloaded, so a delete straight after unloading can fail. That's why the delete tries up to ten times, 500 ms apart. Unloading can also refuse, which is why that retries five times, a second apart. After that it gives up, tells the ops in chat to run /resetworld again, and leaves everyone in the lobby.
If the delete or copy fails after the hardcore worlds have already been unloaded, nothing loads them again until an op runs the command or the server is restarted. A player who logs in during that gap gets an error instead of a friendly message, because I never made joining handle a missing world. There are no automated tests.
What's next
The plugin is shipped and did its job for the challenge, so I have no plans for it beyond the gaps below. There is no per-run statistics file beyond the run number and start time, so nothing remembers how long past runs lasted or what killed everyone. Difficulty is forced to hard with no setting for it. A template with no nether or end gets a freshly generated one, and I haven't done anything cleverer than that. The missing-world state above also needs handling.
- Stack
- Java 21, Paper API 1.21.11, Maven
- Size
- About 690 lines of Java and config
- Status
- Shipped
- Code
- Not public