This article is the second in a series of articles, you can find the first here.

Updating WorldEdit to Minecraft 1.13 has been a long and arduous process. With weeks of hard work, and hundreds of thousands of lines of code changed, it's finally in a complete state.

It's not without significant changes, however, and this article will cover them. Many of these changes bring WorldEdit into the modern era of Minecraft, as we had not upgraded many internal systems in a fair while.

User-Facing Changes

Firstly, I'll go over the user-facing changes. These are minimised where possible, except in some places they had to happen. The areas these mostly cover are block parsing and schematics.

Block Parsing

Due to the significant changes to blocks and IDs in 1.13, block parsing required an entire rewrite. The officially supported format for referencing blocks is to use the official Minecraft format. For example, grass blocks are used by typing minecraft:grass_block, and a snowy grass block would be accessed by typing minecraft:grass_block[snowy=true]. If the block is from the vanilla game, minecraft: can be omitted. For example, grass_block[snowy=true] will still place a snowy grass block.

To retain some aspect of legacy support, you can still reference most legacy numeric IDs. Doing this is, however, NOT officially supported. Placing wool using their colour is still supported (Eg, red places red_wool).

Schematics

Schematics also required significant changes, but have retained legacy compatibility. As the MCEdit Schematic format leverages numerical IDs, WorldEdit has moved to the Sponge Schematic Format. The Sponge Schematic Format is very future proof and will be the supported way of saving and loading schematics going forwards. An added benefit of using this schematic format is that schematics now work correctly with mods and save entities and biomes.

For the end-user, the transition period should be relatively seamless. However, previously created schematics will still load, with some oddities such as corner stairs losing their corner pieces due to format restrictions. Any newly created schematic will use the Sponge format. Any schematic generated on 1.13 will not be usable on prior Minecraft versions. Schematics, like Minecraft worlds, are not guaranteed to be backwards compatible.

Everything else should still function the same. If you find an issue, please report it on our issue tracker.

Developer Changes

This section is much larger and much less backwards compatible than the user-facing changes. Due to a large number of changes in 1.13, and the massive size and technical debt of the WorldEdit codebase, we decided to remove all deprecated or functionally deprecated code from the plugin. Any plugin using deprecated code will no longer function. However, any plugin accessing WorldEdit would have most likely had to be updated anyway. A vast majority of these API calls were deprecated for over four years, so there has been plenty of warning.

Registries

The most obvious change is the removal of the BlockID class. WorldEdit now uses a registry system, in BlockTypes. The equivalent also exists for ItemID. The BlockType.get(String) method gets a BlockType from a namespaced string ID from the registry. The equivalent exists for all of the registries. The following registries currently exist in WorldEdit 7:

  • BlockType
  • ItemType
  • FluidType (In 1.13, Mojang moved fluid blocks to a separate system. This is currently unused, however)
  • EntityType
  • BlockCategory (Mirrors the vanilla Tag system)
  • ItemCategory
  • FluidCategory
  • GameMode
  • WeatherType

Another change is the migration of everything BukkitUtil to the BukkitAdapter class. Previously we spread methods across both files, which confused developers.

Block Material

In WorldEdit 6 and earlier, a file called BlockType shared the name of the new BlockType class. This class contained a list of blocks, as well as some utility functions regarding blocks. These utility functions now reside in Blocks, as well as BlockMaterial. Materials can be accessed via the BlockType#getMaterial() method.

Properties

Also relating to blocks, in 1.13 properties have replaced the metadata system. WorldEdit can now access these. In prior versions, there was a class called BaseBlock. Whilst this class still exists, it has a very different purpose now. Most usages of BaseBlock should now be BlockState. BlockState instances are both immutable and cached. Developers should never create instances of BlockState. This system keeps memory usage down and performance high. Creating new instances would prevent this and cause other issues. You access properties by name on BlockType, and values can be applied and retrieved in BlockState. Applying a property to a BlockState returns a copy of that BlockState with the property applied. There will only be a single BlockState object made for each type and combination of properties, meaning object reference equality works.

NBT Data

When dealing with NBT Data, BaseBlock should be used. Instances are created by passing both a BlockState and a CompoundTag to the constructor. When getting blocks from the world, use getBlock() to get the block itself, and getFullBlock() to get the block with NBT data.

Selections

Another significant change is the Selection API, however this only impacts Bukkit plugins using the 'native layer'. We removed the native layer to standardise WorldEdit across various platforms and clean up the codebase. This layer was first talked about by sk89q back in 2013 on his blog.

To get a selection using WorldEdit 7, you need to do the following:

  1. Get a WorldEdit player using BukkitAdapter.adapt(Player)
  2. Get the LocalSession for the player using WorldEdit.getInstance().getSessionManager().get(Player)
  3. Call LocalSession#getSelection(World) using the WorldEdit Player's World.

This method returns a Region object. From here, you can call many functions on the region and iterate over it to get all of the containing BlockVectors. You can also check and cast into various shapes, such as CuboidRegion or PolygonalRegion.

If no selection exists when calling this code, getSelection(World) will throw an IncompleteRegionException. This exception should be caught and shown to the user.

Schematics

We also made significant changes to the schematic system. Other plugins can now register schematic formats, and we implemented the Sponge Schematic Format. It is now the recommended format to use, and we've deprecated usage of the MCEdit format for all non-legacy import purposes. As the old MCEdit format does not support the way Minecraft works in modern versions, the API can also only load these, not save them.

Schematic formats should be accessed using BuiltInClipboardFormat.SPONGE_SCHEMATIC or BuiltInClipboardFormat.MCEDIT_SCHEMATIC to access specific formats, by using ClipboardFormats.findByAlias(String) to find formats by name, or by using ClipboardFormats.findByFile(File) to identify the format of a schematic file.

A more in-depth tutorial on this API change is available here.

If you have any issues with the API, please join the WorldEdit discord.

General API

WorldEdit also now includes a much larger general Minecraft API for writing cross-platform plugins. Developers can use this to make their plugins work across Sponge, Spigot, Forge, Fabric, etc. This system has been utilised in WorldGuard to make the plugin much more abstract; however, it still only supports Bukkit.

Part 3, focusing on the changes to WorldGuard, can be found here.

We've devoted countless hours to working on this project. If you'd like to support us, we have a GitHub Sponsors. Thanks 😁

About the Author

Maddy Miller

Hi, I'm Maddy Miller, a Senior Software Engineer at Clipchamp at Microsoft. In my spare time I love writing articles, and I also develop the Minecraft mods WorldEdit, WorldGuard, and CraftBook. My opinions are my own and do not represent those of my employer in any capacity.