How to Load and Save Schematics with the WorldEdit API

Posted on December 03, 2018 in minecraft

Tagged with: worldedit, tutorial
How to Load and Save Schematics with the WorldEdit API

Asking how to load, save, paste, and copy schematics are some of the most frequent questions we get about the WorldEdit API. To help with this, I've created a simple guide that covers the basics.

If you're not a developer and want to load and save schematics in-game, see here.

Loading

Loading a schematic from a file is relatively simple now. In WorldEdit 7 we modified the API to allow other plugins to register new formats, as well as better support for multiple formats. Because of this, you can quickly load a clipboard from a file without knowing what kind of schematic it is.

The ClipboardFormats file is the centre of this system, containing a few methods to help you find what format something is. You can get by file with findByFile, or get by registered alias with findByAlias.

Once you have the schematic format, you'll want to create an InputStream from the file (such as a FileInputStream). With that, you can call getReader(InputStream) to get a copy of a ClipboardReader, which provides read() to obtain a Clipboard. ClipboardReaders are Closeable, meaning they support try-with-resources statements.

The following code is a complete example:

ClipboardFormat format = ClipboardFormats.findByFile(file);
try (ClipboardReader reader = format.getReader(new FileInputStream(file))) {
   Clipboard clipboard = reader.read();
}

Pasting

Once you've loaded a schematic, you'll probably want to paste it somewhere.

Pasting makes use of the WorldEdit EditSession class. An instance can be obtained from the EditSessionFactory provided by WorldEdit at WorldEdit.getInstance().getEditSessionFactory(). You'll want to pass it the world you want to paste into, as well as -1 to signify that you don't want to limit the number of blocks it can paste.

Next, you want to take the clipboard you have, and wrap it in a ClipboardHolder. Do this by using the constructor that takes a Clipboard. On the holder object, you can set a transform and create a PasteBuilder.

To start the pasting process, call createPaste(EditSession) with the EditSession you created earlier. There are a few options on the PasteBuilder, such as to and ignoreAirBlocks. Providing a BlockVector3 to to(BlockVector3) allows you to specify where the code will paste the schematic. The ignoreAirBlocks option lets you ignore any air blocks in the schematic when pasting, causing it to keep whatever is already in the world rather than removing it.

Once you've set the correct options on the PasteBuilder, call build to receive an Operation. Operations are what WorldEdit uses to modify the world. In this case, the operation it returns is one that pastes a clipboard. They are run using the Operations.complete(Operation) method.

It's also best practice (and in many cases required) to flush EditSession instances after completing the edits. Flush the session by calling editSession.flushSession();, or by wrapping the creation of it in a try-with-resources statement.

The following code is a complete example:

try (EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1)) {
    Operation operation = new ClipboardHolder(clipboard)
            .createPaste(editSession)
            .to(BlockVector3.at(x, y, z))
            .ignoreAirBlocks(false)
            .build();
    Operations.complete(operation);
}

Copying

To copy a structure from the world into a Clipboard, you'll need to create a CuboidRegion. Firstly, make a BlockVector3 of both the minimum and maximum points of the region, and then use them in the constructor CuboidRegion(World, BlockVector3, BlockVector3) alongside the world to get a region object.

Then create a BlockArrayClipboard, passing in the region. Next, you need to make an EditSession, the same way as explained in the section on pasting.

To copy this region into the clipboard, you need to use a ForwardExtentCopy. This class represents an operation that copies from one extent to another. In this case, from the EditSession to the BlockArrayClipboard. The constructor arguments you use should be the EditSession, the region, the clipboard, and the region's minimum point. If you wish to copy entities, you can set the setCopyingEntities method to true on the operation.

From here you can just run the operation with Operations.complete and the region area will be copied into the clipboard. From here, you can use a clipboard to paste elsewhere or save to a schematic.

The following code is a complete example:

CuboidRegion region = new CuboidRegion(world, min, max);
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);

EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(region.getWorld(), -1);

ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
forwardExtentCopy.setCopyingEntities(true);
Operations.complete(forwardExtentCopy);

Saving

To save a clipboard to file, you must first choose what format you're saving in. Currently, as of writing, the Sponge Schematic Format is the recommended one. This is accessed via BuildInClipboardFormat.SPONGE_SCHEMATIC.

From here, create an OutputStream (such as a FileOutputStream) and pass it to the getWriter(OutputStream) method of the ClipboardFormat to get a writer. Call write(Clipboard) and pass in the clipboard to write to the file. Don't forget to close the writer, or use a try-with-resources statement, so that the changes get flushed to disk.

The following code is a complete example:

try (ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) {
    writer.write(clipboard);
}

Register a custom Schematic Format

Have a Schematic Format you want to integrate with WorldEdit? To do this, you'll need to implement the following classes:

  • ClipboardFormat
  • ClipboardReader
  • ClipboardWriter

To ensure that you don't interfere with other formats, make sure that the isFormat method in ClipboardFormat returns true if and only if it is the format you're implementing.

Once done, call ClipboardFormats.registerClipboardFormat with your newly implemented format. From now on any calls to findByFile or findByAlias will include your format.

Further Help

If you still need help, ask on the official EngineHub discord guild.

Another resource is the WorldEdit Developer Documentation, which explains the various concepts used in the WorldEdit API.

Check out these popular related posts!

How to use MCEdit Schematics in Minecraft 1.13, 1.14, 1.15, 1.16, and newer!

Posted on January 15, 2020

MCEdit no longer exists for new Minecraft versions, so how should you use schematic files now? We have the solution! Use MCEdit Schematic files in Minecraft 1.13, 1.14, 1.15, 1.16, and newer.

How to save and load schematics with WorldEdit

Posted on June 27, 2019

Learn how to load and paste schematic files into Minecraft with WorldEdit, and even make your own to share with friends or the internet!

How to use WorldEdit with Modded Blocks

Posted on May 09, 2020

Using WorldEdit with blocks added by mods on versions of Minecraft before 1.13 can be confusing, but there are a few ways to make it simple