If you’re just interested in doing this on your own SMP server, follow the instructions over at gitlab.

Why?

I run a small SMP server for some friends, we run Paper with almost no plugins except for discord sync, worldguard, coreprotect and some metrics stuff. Recently one guy on our server started working on a quake like pvp arena (pvp is off, as the majority wanted it off, worldguard allows us to enable it in some areas anyway). My first thought when he started working on this was already that respawn anchors would be a cool addition to this. Unfortunately as this came out with the 1.16 nether update this is entirely designed for the nether, and like beds in the nether it will explode when you try using it in a dimension where it is not meant to be used. Fortunately Paper provides a quite extensive plugin interface, so off I went trying to disable the exploding, so let’s give this a go.

Figuring out how

I quickly ran into the BlockExplodeEvent, which had a setCancelled(boolean) method. So I quickly tried the following.

@EventHandler
public void onBlockExplode(final BlockExplodeEvent event) {
    event.setCancelled(true);
}

And surely enough this seemed to work. Except that the respawn anchor just completely disappeared and it didn’t seem like I could retrieve a Player object anywhere here to actually set the spawn point. Let’s move on then. Then I quickly ran into PlayerInteractEvent which will get triggered whenever you interact with a block. So I tried the following, which pretty much emulates how the respawn anchor is supposed to work.

@EventHandler
public void onInteractBlock(final PlayerInteractEvent event) {
    if (!(event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK)) return;
    if (event.getClickedBlock() == null) return;

    if (event.getClickedBlock().getType() == Material.RESPAWN_ANCHOR) {
        RespawnAnchor anchor = (RespawnAnchor) event.getClickedBlock().getBlockData();
        if (anchor.getCharges() >= 1) {
            boolean isGlowstone = event.getPlayer().getEquipment().getItem(event.getHand()).getType() == Material.GLOWSTONE;
            if (!isGlowstone || anchor.getCharges() == anchor.getMaximumCharges()) {
                event.setCancelled(true);
                event.getPlayer().setBedSpawnLocation(event.getClickedBlock().getLocation(), true);
            }
        }
    }
}

After this I booted up my test world, charged the respawn anchor with glowstone. Right clicked. And, nothing happend. No explosion, no “Respawn point set message”. As it turns out using setBedSpawnLocation doesn’t send this message, good to know. But I killed myself ingame. To only appear at spawn with the typical message “You have no home bed or charged respawn anchor, or it was obstructed”. Uhm ok then. After a bit more trail and error it turned out this did work perfectly fine if the specified location in setBedSpawnLocation would point to a respawn anchor in the nether or a bed in the overworld. Back to the drawing board I guess.

Not much later I ran into a new feature that also got introduced with 1.16, this feature being custom dimensions. More specifically, I was interested part where you could make your own dimension type. As this has settings like piglin_safe, bed_works and most importantly respawn_anchor_works. So I quickly threw a datapack together that would specify a custom dimension type which I appropriately called schoentoon:overworld, as it is recommended and always good practice to work in your own namespaces. This dimension type would be the same as the regular minecraft:overworld except for respawn_anchor_works. So it looked like the following.

{
  "ambient_light" : 0,
  "bed_works" : true,
  "coordinate_scale" : 1,
  "has_ceiling" : false,
  "has_raids" : true,
  "has_skylight" : true,
  "infiniburn" : "minecraft:infiniburn_overworld",
  "logical_height" : 256,
  "natural" : true,
  "piglin_safe" : false,
  "respawn_anchor_works" : true,
  "ultrawarm" : false
}

I then put the datapack in the datapacks folder. Opened up my NBT editor to change the dimension type in the level.dat file of the overworld (located at WorldGenSettings->dimensions->minecraft:overworld->type). I loaded up the world, without the plugin this time. Gave it a try and it worked. Great, let’s get to integrating this with worldguard so I can toggle in certain locations of the map. But this time we’ll have to work the other way around, as we want to re-enable the exploding feature in certain areas. As now the default behavior in the overworld is to work as in the nether and not explode. At that point I quickly got to the final stage of the plugin, to not clutter this post with too much code I would like to direct you to Gitlab for this instead.

One day later I decided to install this on our actual server. So I installed the datapack and the plugin. Logged onto the server, ran /region flag quake_arena respawn-anchor-explode deny. Where quake_arena is the worldguard region and respawn-anchor-explode the flag that the plugin checks for to know whether it should explode or not. After this I quickly tested it and it all seemed to work. As you may expect that’s of course when issues started to arrive.

Issues

Barely half an hour after I had first installed it on our SMP server, I received this picture from someone on the server. Broken end portal Basically he didn’t get teleported back to the overworld as is supposed to happen. Meaning he was stuck in the end dimension, unless he would have killed himself. So I logged in again, teleported him back to the overworld. And went back to testing. As it turns out the end portal tries to teleport you to a dimension of type minecraft:overworld and as of the current latest release (1.16.3) there doesn’t seem to be a way to change this. So even though I didn’t really want to, I changed the namespace of my datapack from schoentoon:overworld to minecraft:overworld. Changed back the NBT data to minecraft:overworld as well. And to my surprise, the respawn anchors kept working.

About one week later of course yet another accident happened related to this. A player who only recently joined our server and had not encountered respawn anchors yet, decided to play around with the one set up in our nether hub. Only to find out that because I never set the respawn-anchor-explode flag to deny in the nether, it was exploding. Thankfully this was quickly fixed quickly running /region flag __global__ respawn-anchor-explode deny in the nether, where __global__ is the special WorldGuard ‘region’ that applies to the entire dimension. It surely was hilarious though.