Plugin Tasks

A Minecraft world contains several different kinds of data. The blocks in the world are fundamentally different from the monsters and animals that wander through it, and some blocks contain data that is more complex than a single block ID. Blocks and entities are organized into chunks, and there is additional data that applies to each entire chunk, and there is also metadata that describes the world dimension that contains these chunks, and that describes the save file as a whole. These tasks will guide you in editing each of these different aspects of the save file.

World Dimensions

A Minecraft save file contains several world dimensions, which include the Overworld, The Nether, The End, and any other dimensions added by game mods. MCEdit only allows the user to view and edit one of the world’s dimensions at any time, so plugins will often be given a dimension object that refers to the world dimension that the user is currently editing. All of the following tasks will refer to this dimension object.

Editing Blocks

Blocks are the defining element of a Minecraft dimension and are the simplest to deal with. Blocks are stored in a three dimensional grid extending from the bottom of the world to the build height - in other words, from Y=0 to Y=255. Every position in the grid will have a block. If a block appears to be empty, it will really contain the block air.

The position of a block is given by its X, Y, and Z coordinates. The type of the block at that position is given by its identifier, which is a short string of text such as minecraft:air, minecraft:stone, or minecraft:stone[variant=diorite]. Internally, this identifier is stored as a pair of integers. When editing the world, you may use either the string of text or the pair of integers to specify a block type, but it is recommended to use the string of text, for both readability and for compatibility.

NOTE: When using block types added by mods, you must use the text identifier, because the integer IDs will vary from world to world.

Alternately, you may pass a BlockType instance. A BlockType instance may be obtained by presenting a block type input to the user (e.g. using an option with type="blocktype" in a SimpleCommandPlugin or by constructing a BlockTypeButton yourself). BlockTypes may also be found by looking up a textual or numeric ID in the dimension’s blocktypes. To wit:

stone = dimension.blocktypes['minecraft:stone']
granite = dimension.blocktypes['minecraft:stone[variant=granite]']
cobblestone = dimension.blocktypes[1]  # don't do this!
podzol = dimension.blocktypes[3, 2]    # don't do this either!

dimension.setBlock(0, 0, 0, granite)   # etc.

To discover which block is at a given position, call dimension.getBlock, which will return a BlockType instance.

WorldEditorDimension.getBlock(x, y, z)[source]

Returns the block at the given position as an instance of BlockType. This instance will have id, meta, and internalName attributes that uniquely identify the block’s type, and will have further attributes describing the block’s properties. See BlockType for a full description.

If the given position is outside the generated area of the world, the minecraft:air BlockType will be returned.

Parameters:
  • x (int) –
  • y (int) –
  • z (int) –
Returns:

block

Return type:

BlockType

To change the block at a given position, call dimension.setBlock

WorldEditorDimension.setBlock(x, y, z, blocktype)[source]

Changes the block at the given position. The blocktype argument may be either a BlockType instance, a textual identifier, a tuple containing a textual identifier and a block metadata value, or a tuple containing a block ID number and a block metadata value.

This function will change both the ID value and metadata value at the given position.

It is recommended to pass either a BlockType instance or a textual identifier for readability and compatibility.

Parameters:
  • x (int) –
  • y (int) –
  • z (int) –
  • blocktype (BlockType | str | (str, int) | (int, int)) –
Returns:

block

Return type:

BlockType

Array-based, high performance variants of these two methods are available. When given parallel arrays of x, y, z coordinates, dimension.getBlocks will return an array of the same size containing the block IDs at those coordinates. If requested, it will also return the block metadata values, light values, and/or biome values for those coordinates at the same time.

Likewise, dimension.setBlocks may be given parallel arrays of x, y, z coordinates along with arrays of any of the following: block IDs, block metadata values, light values, biome values. To set all coordinates to the same value, you may pass a single value instead of an array.

WorldEditorDimension.getBlocks(x, y, z, return_Blocks=True, return_Data=False, return_BlockLight=False, return_SkyLight=False, return_Biomes=False)[source]
WorldEditorDimension.setBlocks(x, y, z, Blocks=None, Data=None, BlockLight=None, SkyLight=None, Biomes=None, updateLights=True)[source]

Editing Entities

Entities are the free-roaming elements of a Minecraft world. They are not bound to the block grid, they may be present at any position in the world, and may even overlap. Animals, monsters, items, and experience orbs are examples of entities.

Since entities may be at any position, you cannot specify an entity with a single x, y, z coordinate triple. Instead, you may create a BoundingBox (or any other SelectionBox object) and ask MCEdit to find all of the entities within it. You may even ask it to find only the entities which have specific attributes, such as id="Pig" to find only Pigs, or name="Notch" to find entities named “Notch”. This is all done by calling dimension.getEntities

WorldEditorDimension.getEntities(selection, **kw)[source]

Iterate through all entities within the given selection. If any keyword arguments are passed, only yields those entities whose attributes match the given keywords.

For example, to iterate through only the zombies in the selection:

for entity in dimension.getEntities(selection, id=”Zombie”):
# do stuff
Parameters:
  • selection (SelectionBox) –
  • kw (Entity attributes to match exactly.) –
Returns:

entities

Return type:

Iterator[EntityRef]

It is important to know that this function only returns an iterator over the found entities. If you assign one of these entities to another variable (or put it into a container such as a list or dict) then that entity will keep its containing chunk loaded, which may possibly lead to out-of-memory errors. Thus, it is best to simply modify the entities in-place while iterating through them rather than hold references to them.

The entities are returned as instances of EntityRef. An EntityRef is a wrapper around the underlying NBT Compound Tag that contains the entity’s data. The EntityRef allows you to change the values of the entity’s attributes without having to deal with the individual tags and tag types that represent those attributes.

In other words, instead of writing:

entity["Name"] = nbt.TAG_String("codewarrior0")

You only have to write:

entity.Name = "codewarrior0"

However, it may occasionally be useful to access the entity’s NBT tags directly. This can be done using the entity.raw_tag attribute. After modifying the raw_tag, you must always mark the entity as dirty by doing entity.dirty = True to ensure your changes are saved:

import nbt
tag = entity.raw_tag()
tag["Name"] = nbt.TAG_String("codewarrior0")
entity.dirty = True

Creating entities

TODO: Describe creating entities, either by calling dimension.worldEditor.EntityRef.create(entityID) or by crafting the entity’s tag by hand.