mciwb#

Minecraft Interactive World Builder: build in a Minecraft world from Python.

The main entry point is Iwb, which connects to a Minecraft server. The building blocks (Vec3, Item, Direction, Volume, polygon etc.) come from the mcwb library. These and the classes below can all be imported from mciwb.imports. mciwb.builders has higher level building blocks: roofs, arches, stairways, foundations and schematic files.

Read and draw regions with scan and render from the mciwb.render module (or mciwb.imports). They are not imported here, where a function called render would hide the mciwb.render module.

mciwb.__version__: str#

Version number as calculated by pypa/setuptools_scm

Submodules

render

Render a region of a Minecraft world to an image, so that you (or an AI agent) can see what a build looks like without joining the game.

builders

Higher level building blocks: roofs, arches, columns, stairways, roads, foundations that follow the terrain, and Sponge schematic files.

Members

Iwb

Interactive World Builder class.

get_world

Return the current Iwb world object, i.e. the most recently created one.

Player

Represent a player in the world and provide functions for monitoring their position and direction they are facing.

PlayerNotInWorldError

The player (or named entity) could not be found in the world.

CopyPaste

Provides an interactive way to use copy and paste commands within a Minecraft world.

Signs

Monitor the world for signs placed by a player.

Wall

Draw walls between pairs of points in the world.

WallMaker

Build walls interactively with command signs.

Switch

Defines a class for representing a lever, button or any other activator in the world.

Monitor

A class to provide threads for monitoring.

Client

An RCON client for Minecraft Java Edition that copes with the other RCON clients of the server.

get_client

Retrieve the client for the current thread.

set_client

Set the client for this thread.

new_thread

Create a thread with its own RCON Client connection stored in thread local storage.

parse_nbt

Naive deserialization of an SNBT string into a object graph of Python types.

Backup

Backup and restore a Minecraft world folder.

MinecraftServer

Create and monitor Minecraft servers on the local machine using Podman

BlockGrid

The blocks of a cuboid region of the world.

Palette

The colours of blocks, see the module documentation for the rules.

class mciwb.Iwb(server: str = 'localhost', port: int = 20100, passwd: str = 'default_pass')[source]#

Interactive World Builder class. Provides a very simple interface for interactive functions for use in an IPython shell, or in scripts.

Connect to the server started by mciwb start with:

world = Iwb()

Call stop when finished to stop any background monitoring threads.

Variables:
  • player – The default Player object.

  • copier – CopyPaste object for the above player.

  • signs – The Signs object for the above player.

  • world_folder – The server’s world folder, if it is on this machine. scan and render read blocks from its files, which is much faster than over RCON. Set for the server of mciwb start when it uses the default --folder: for another folder, set it yourself, e.g. world.world_folder = Path("/my/server/world").

Initialise the world object.

Parameters:
  • server – the server address, defaults to the local server started by mciwb start

  • port – the server’s RCON port

  • passwd – the server’s RCON password

Raises:

SessionTimeout – if the connection to the server fails

debug(enable: bool = True)[source]#

Enable/disable debug log. Enabling this will also enable full Traceback log.

Parameters:

enable – True to enable debug log, False to disable

backup(name: str | None = None) → None[source]#

Backup the Minecraft world to a file. If no name is given then the backup will be named using the current date and time.

Parameters:

name – the name of the backup file

connect() → Client[source]#

Makes a connection to the Minecraft Server. Can be called again if the connection is lost e.g. due to server reboot.

get_player(name: str) → Player[source]#

Get the player object for the given player name.

Parameters:

name – the name of the player

property players: list[str]#

Get a list of the names of players being monitored.

add_player(name: str, me: bool = True, setup: bool = True)[source]#

Add a player to the world object. This provides monitoring of the player’s position and handles the player’s placing of action signs. The player is also given a set of the action signs.

If me is True then the player will be set as the current default player. The default player is available using:

Iwb.the_world.player

All players are available using:

Iwb.the_world._players
Parameters:
  • name – the name of the player

  • me – if True, set this player as the default player

  • setup – if True, make the player an operator in creative mode

stop()[source]#

Stop all background monitoring threads. Call this when finished with the world, e.g. at the end of a script.

set_block(pos: Vec3, block: Item, facing: Vec3 | None = None, nbt: list[str] | None = None) → bool[source]#

Places a block in the world

Parameters:
  • pos – the position to place the block

  • block – the type of block

  • facing – the direction the block should face (if applicable)

  • nbt – a list of block states to apply to the block

nbt examples:

Placing a top half of a door, open, with hinge on the left:

nbt=[“half=upper”, “hinge=left”, “open=true”]

Returns:

True if the block is now in place. False if the server rejected the command (the server’s response is logged as an error)

place_door(pos: Vec3, door_type: Item, facing: Vec3 = (0, 0, -1), open: bool = False, right_hinge: bool = False) → None[source]#

Place a door in the world (doors are 2 blocks high)

Parameters:
  • pos – the position of the bottom half of the door

  • door_type – the type of door to place e.g. Item.OAK_DOOR

  • facing – the direction the door should face

  • open – whether the door should be open or closed

  • right_hinge – True for a hinge on the right, False for the left

get_block(pos: Vec3) → Item[source]#

Gets a block in the world

Parameters:

pos – the position to get the block from

save(filename: str | Path, vol: Volume | None = None)[source]#

Save a Volume of blocks to a file. The volume can be specified in the vol parameter or alternatively defaults to the current copy buffer.

The file is saved in the mcwb format which is a JSON file containing a 3d array of Item objects. If the filename ends in .schem it is saved as a Sponge schematic instead, with the block states of stairs, slabs and logs (see mciwb.builders.Schematic.from_world), which other Minecraft tools such as WorldEdit can load.

The file can be loaded into a world using the load method.

Parameters:
  • filename – the name of the file to save to

  • vol – the volume to save

Raises:

ValueError – if no vol is given and there is no copy buffer

load(filename: str | Path, position: Vec3 | None = None, anchor: Anchor3 = Anchor3.BOTTOM_SW)[source]#

Load a saved set of blocks into a location. The location can be specified in argument position or alternatively defaults to the copy buffer start position.

The blocks are loaded from a file in the mcwb format which is a JSON file containing a 3d array of Item objects, or from a Sponge schematic if the filename ends in .schem (see mciwb.builders.Schematic).

The blocks are loaded into the world using the Blocks class.

Parameters:
  • filename – the name of the file to load from

  • position – the position to load the blocks to

  • anchor – the anchor point for the blocks

Raises:

ValueError – if no position is given and there is no copy buffer

scan(start: Vec3, end: Vec3) → BlockGrid[source]#

Read the blocks between two opposite corners of a region, from the world’s files if world_folder is set, otherwise over RCON.

Parameters:
  • start – a corner of the region

  • end – the opposite corner of the region

Returns:

the blocks, e.g. world.scan(a, b).counts() counts them

render(start: Vec3, end: Vec3, file: str | Path = 'render.png', views: Sequence[str] = ('top', 'iso'), scale: int | None = None, labels: bool = True) → BlockGrid[source]#

Render the region between two opposite corners to a PNG image, to see what a build looks like. See Render a Build to an Image for the views.

Parameters:
  • start – a corner of the region

  • end – the opposite corner of the region

  • file – the image file to write

  • views – the views to draw: top, iso, north, south, east, west, iso_ne, iso_nw or iso_sw; a list, or the name of one view

  • scale – pixels per block, chosen automatically by default

  • labels – add titles and world coordinate labels

Returns:

the blocks that were rendered, see scan

cmd(cmd: str, expect: str | None = None) → str[source]#

Run any arbitrary Minecraft console command on the server.

The server’s reply is returned as it is, including error messages such as Incorrect argument for command...<--[HERE]. (On Minecraft 26.x, for example, game rules have snake case names, so gamerule doDaylightCycle is an error: use gamerule advance_time. And time query daytime is an error too: use time query day for the ticks into the current day, and time query day repetition for the number of days.)

Changed: before mciwb#166 the errors that mcipc recognises were raised as mcipc exceptions (e.g. InvalidArgument); now they are returned as text like any other reply.

Another RCON client of the server (e.g. a dashboard) can, rarely, garble the reply: empty it or add its own output to it. Pass expect to check the reply and send the command again if needed. Only do that for a command that is safe to send twice (e.g. setblock, tp to a fixed place, gamerule ..., but not give or summon).

Parameters:
  • cmd – the command to run, without the leading slash e.g. “time set day”

  • expect – a regular expression that the reply must contain, e.g. r"Game rule \S+ is currently set to \S+"

Returns:

the server’s response. With expect, just the part of it that matched, or the whole response if it never matched

mciwb.get_world() → Iwb[source]#

Return the current Iwb world object, i.e. the most recently created one.

class mciwb.Player(name: str)[source]#

Represent a player in the world and provide functions for monitoring their position and direction they are facing.

Creating a Player only reads from the world. Call setup to make the player an operator in creative mode (Iwb.add_player does this).

Parameters:

name – the name of the player, or the CustomName of any other entity

setup() → None[source]#

Make the player an operator in creative mode, so that they can use command signs and build freely.

property inventory: list[str]#

Get the player’s inventory

property pos_f: Vec3#

Return the player’s precise position

property pos: Vec3#

Return the player’s block position

property facing: Vec3#

Return the player’s facing direction

Returns:

a Vec3 representing the direction the player is facing NORTH = Vec3(0, 0, -1) SOUTH = Vec3(0, 0, 1) EAST = Vec3(1, 0, 0) WEST = Vec3(-1, 0, 0)

property rotation: tuple[int | str, int | str] | str#

Get the player’s rotation in degrees

player_in(volume: Volume) → bool[source]#

Check if the player is inside the Volume

Parameters:

volume – the volume of blocks to check

classmethod players_in(volume: Volume) → list[str][source]#

return a list of player names whose position is inside the Volume

exception mciwb.PlayerNotInWorldError[source]#

The player (or named entity) could not be found in the world.

class mciwb.CopyPaste[source]#

Provides an interactive way to use copy and paste commands within a Minecraft world.

to_volume() → Volume[source]#

Converts the copy buffer location and dimensions to a Volume

apply_volume(vol: Volume)[source]#

Use a Volume to set the copy buffer location and dimensions. The paste point is set to the start of the Volume.

get_commands()[source]#

return a list of command names and the callback functions they represent. For use in setting up a Signs object that can be used to interactively call the copy paste functions.

select(pos: Vec3)[source]#

Select a new copy buffer start point in the world. The previous start point becomes the stop point (i.e. opposite corner of the paste buffer)

paste(pos: Vec3, force=True)[source]#

Copy the contents of past buffer to pos

paste_safe(pos: Vec3)[source]#

Paste the contents of the paste buffer to pos, but only if the paste buffer does not overlap with the target area

fill(pos: Vec3 = (0, 0, 0), item: Item = Item.AIR)[source]#

fill the paste buffer offset by pos with Air or a specified block

Parameters:
  • pos – offset from the paste buffer start point

  • item – block to fill with

clear(_: Vec3 = (0, 0, 0))[source]#

Clear the blocks in the current paste buffer

expand_to(pos: Vec3)[source]#

expand one or more of the dimensions of the copy buffer by moving the faces outwards to the specified point

expand(x=0, y=0, z=0)[source]#

expand one or more of the dimensions of the copy buffer by relative amounts

class mciwb.Signs(player: Player)[source]#

Monitor the world for signs placed by a player. Perform an action based on the text of the sign.

Each sign object can be used to monitor the placing of signs by a single player. The object can be hooked to functions that are to be called when a sign is placed by the player.

By default each Sign object is initialized with select/copy/paste functions. Additional signs with callback functions can be added.

For best results, use the bound methods of an object for the callback functions. That way the user code can manage state within the object providing those functions.

poll()[source]#

check if a sign has been placed in front of the player 1 to 3 blocks away and take action based on sign text

do_action(command: str, target: Vec3, block_pos: Vec3)[source]#

Perform an action based on the text of the sign. The action is to call the callback function that is configured for this sign text.

Parameters:
  • command – the text of the sign

  • target – the target block that the sign indicates

  • block_pos – the position of the block that the sign is on - this is cleared if the sign is used

add_sign(name: str, function: Callable[[Vec3], None])[source]#

Add a new sign type with its action callback function

Parameters:
  • name – the text of the sign

  • function – the callback function to be called when the sign is placed

remove_sign(name: str)[source]#

Stop monitoring for a sign with the given name

Parameters:

name – the text of the sign

classmethod sign_block(text: str) → str[source]#

Return the block state and NBT for a standing oak sign with the given text. For use with setblock, e.g. to place a command sign from code.

Parameters:

text – the text for the first line of the sign

classmethod sign_item(text: str) → str[source]#

Return the item stack for an oak sign that is placed with the given text already written on it. For use with the give command.

Parameters:

text – the text for the first line of the sign

give_signs()[source]#

Give player one of each command sign in our commands list

Check first if the player has the sign already

class mciwb.Wall(height: int | None = None, item: Item | str = Item.STONE, profile: list[Any] | None = None)[source]#

Draw walls between pairs of points in the world.

A wall is drawn column by column along the line from its start to its end. The profile describes the columns, and is repeated along the length of the wall:

  • the profile is a list of columns

  • each column is a list of blocks, from the top of the column down

  • each block is an Item, or a list of Items to make the wall more than one block thick (extending to the right of the direction of drawing)

If the column is shorter than height it is repeated to fill the height.

For example, a castle wall with crenellations on top:

battlement = [Item.AIR, Item.STONE_BRICKS, Item.STONE_BRICKS]
solid = [Item.STONE_BRICKS] * 3
wall = Wall(profile=[solid, battlement])
wall.set_start(Vec3(0, -60, 0))
wall.draw(Vec3(20, -60, 0))
Parameters:
  • height – the height of the wall, defaults to the length of each column in the profile

  • item – the block to build a plain wall from, used when no profile is given

  • profile – the profile of the wall, a list of columns

set_start(pos: Vec3)[source]#

Set the start point of the next wall. The wall is built on top of the block at pos.

Parameters:

pos – the block that the wall starts on

set_end(pos: Vec3)[source]#

Set the end point of the next wall without drawing it.

Parameters:

pos – the block that the wall ends on

draw(end: Vec3 | None = None)[source]#

Draw the wall from the start point to end (or the end point set with set_end). The end becomes the start of the next wall, so calling draw repeatedly draws a connected series of walls.

Parameters:

end – the block that the wall ends on

class mciwb.WallMaker(wall: Wall | None = None)[source]#

Build walls interactively with command signs. Gives the player a ‘start_wall’ sign and an ‘end_wall’ sign. Place ‘start_wall’ to set the start of a wall, then place ‘end_wall’ to draw the wall up to it. Keep placing ‘end_wall’ signs to draw a connected series of walls.

Requires a player added with Iwb.add_player.

Parameters:

wall – the Wall to draw, defaults to a plain stone wall 3 high

remove()[source]#

Stop responding to the wall signs

class mciwb.Switch(position: Vec3, item: Item, callback: Callable[[Switch], None], name: str = '')[source]#

Defines a class for representing a lever, button or any other activator in the world. Implements monitoring of the switch’s state with callbacks.

Parameters:
  • position – the position of the switch in the world

  • item – the item type of the switch (must be one of item_types)

  • callback – the callback to call when the switch’s state changes

  • name – the name of the switch (defaults to “switch” + id)

Variables:
  • id – the id of the switch

  • name – the name of the switch

  • pos – the position of the switch in the world

  • powered – the current state of the switch (True if powered)

  • callback – the callback to call when the switch’s state changes

  • monitor – the Monitor object for the switch

  • switches – the list of all switches in the world

  • next_id – the next id to assign to a switch

  • on – the state to check for a powered switch

  • off – the state to check for an un-powered switch

classmethod remove_named(name: str)[source]#

Remove a switch by name.

remove()[source]#

Remove the switch from the world. Clean up the monitor.

classmethod stop()[source]#

Stop monitoring the state of all switches. The switches stay in the world but their callbacks are no longer called.

check_state(state: str) → bool[source]#

Test the state of one of the switch’s properties.

Parameters:

state – the state to test for, should be one of self.on or self.off

class mciwb.Monitor(func: Callable[[...], Any] | None = None, params: tuple[Any, ...] = (), once: bool = False, name: str | None = None, poll_rate: float = 0.2, start: bool = True)[source]#

A class to provide threads for monitoring. Each thread maintains a list of functions to call repeatedly.

Each thread has its own Client object for parallel execution of Minecraft server functions.

Parameters:
  • func – a function to call in the Monitor thread

  • params – parameters to pass to the above function. Note that func and params can be None, () in which case you must use add_poller_func to add functions to be called.

  • once – if True, stop polling after first poll - use for a single background operation

  • name – name of the thread

  • poll_rate – rate at which to poll the functions

  • start – if True, start the thread immediately

start_poller()[source]#

Begin polling the functions in the pollers list

add_poller_func(func: Callable[[...], Any], params: tuple[Any, ...] = ())[source]#

Add a function to the pollers list

Parameters:
  • func – function to add

  • params – parameters to pass to the function

remove_poller_func(func: Callable[[...], Any])[source]#

Remove a function from the pollers list

Parameters:

func – function to remove

classmethod stop_all(timeout: float = 5.0)[source]#

Stop all instances of Monitor and tidy up. Call this before exiting the program so that background work is finished cleanly.

Parameters:

timeout – seconds to wait for each thread to finish

stop()[source]#

Stop this instance of Monitor

classmethod stop_named(name: str)[source]#

Stop a named instance of Monitor

class mciwb.Client(*args, frag_threshold: int = 4096, **kwargs)[source]#

An RCON client for Minecraft Java Edition that copes with the other RCON clients of the server.

Each command waits for any command running on another connection of this process to complete, so that the server returns the output of this command only.

Other processes can still run commands at the same moment, which can empty our reply or add theirs to it (about 1 in 10000 commands while another client polls the server). So the replies of setblock and fill (except in destroy mode) and loot (as used by mcwb.get_block) are checked, the command is sent again if the reply is lost, and only the command’s own output is returned. Other commands, including clone, are sent once: use retry_command, or Iwb.cmd(..., expect=...), for those that are safe to send again.

Set an optional fragmentation threshold and command in order to detect fragmented packets.

For details see: https://wiki.vg/RCON#Fragmentation

run(command: str, *arguments: str) → str[source]#

Run a command, raising mcipc’s exceptions (e.g. InvalidArgument) for the errors that mcipc recognises

run_raw(command: str, *arguments: str) → str[source]#

Run a command and return the server’s reply as it is, including any error message, rather than raising mcipc’s exceptions

mciwb.get_client() → Client[source]#

Retrieve the client for the current thread.

Every thread needs its own RCON connection. Threads created with new_thread (e.g. by Monitor) get one automatically.

mciwb.set_client(client: Client) → None[source]#

Set the client for this thread. Use this when the client object has been created outside of new_thread.

mciwb.new_thread(client: Client, target: Callable[[], None], name: str) → Thread[source]#

Create a thread with its own RCON Client connection stored in thread local storage.

The thread is a daemon thread so that it can never keep the Python interpreter alive on exit. Use Monitor.stop_all to stop threads cleanly.

Parameters:
  • client – the client whose connection details the new thread copies

  • target – the function to run in the new thread

  • name – the name of the new thread

mciwb.parse_nbt(s_nbt_text: str) → object[source]#

Naive deserialization of an SNBT string into a object graph of Python types.

Note that this is one way only since the following details are lost: - distinction between byte, short, int long, types (suffixes of b,s,none,l) - distinction between float, double types (suffixes of f,d) - distinction between SNBT and raw JSON (enclosed in single quotes)

See https://minecraft.wiki/w/NBT_format

class mciwb.Backup(world_folder: Path = PosixPath('/home/runner/mciwb-server/world'), backup_folder: Path = PosixPath('/home/runner/mciwb-backups'))[source]#

Backup and restore a Minecraft world folder.

Parameters:
  • world_folder – the world folder of the server (containing level.dat)

  • backup_folder – the folder to save backup zip files in

backup(name: str | None = None, running: bool = True) → Path[source]#

Backup the world folder to a zip file in the backup folder.

Parameters:
  • name – the name of the backup file, defaults to the current date and time

  • running – True if the server is running. The server is then told to save everything to disk and pause saving during the backup. This needs an RCON client for the current thread (see get_client)

Returns:

the path of the backup file

Raises:

ValueError – if the world folder is not a Minecraft world

find(name: str | None = None) → Path[source]#

Find a backup file

Parameters:

name – the name of the backup file, defaults to the latest backup

Returns:

the path of the backup file

Raises:

ValueError – if the backup file does not exist

restore(name: str | None = None, backup: bool = False) → None[source]#

Restore the world folder from a backup. The server must be stopped.

The current world folder is replaced. It is kept as a sibling folder with the suffix ‘-old’ if backup is True, and deleted otherwise.

Parameters:
  • name – the name of the backup file, defaults to the latest backup

  • backup – keep the current world folder as ‘<world>-old’

Raises:

ValueError – if the backup file does not exist

class mciwb.MinecraftServer(name: str, rcon: int, password: str, server_folder: Path, world_type: str, keep: bool = True, test: bool = False, version: str = '26.3')[source]#

Create and monitor Minecraft servers on the local machine using Podman

Parameters:
  • name – the name of the server

  • rcon – the rcon port for the server

  • password – the rcon password for the server

  • server_folder – the folder to store the server files in

  • world_type – the type of world to create (a world preset such as “normal” or “flat”)

  • keep – keep the server running: the container has the “always” restart policy, so podman-restart.service restarts it after a reboot, and remove does nothing unless forced

  • test – run the server in test mode (a flat world without structures or mobs, regenerated by each create)

  • version – the Minecraft Java Edition release to run. Note that an existing world is upgraded if it is opened with a newer release

Create a MinecraftServer object only. Use create to spin up the container.

wait_server()[source]#

Wait until the server is ready to accept rcon connections

Raises:

RuntimeError – if the container stops, or the server does not accept connections within start_timeout seconds. The error includes the end of the server log.

stop()[source]#

Stop the minecraft server

start()[source]#

Start the minecraft server

remove(force=False)[source]#

Remove a minecraft server container

Parameters:

force – force the removal of the container

create(force: bool = False) → None[source]#

Spin up a minecraft server in a container, creating a new world if the server folder has none.

If the container already exists it is reused (and started if it is stopped) with the settings that it was created with. Use force, or mciwb stop, to recreate it with new settings.

Parameters:

force – force the server to be removed if it already exists

classmethod stop_named(name: str)[source]#

Stop a minecraft server by name

Parameters:

name – the name of the server to stop

class mciwb.BlockGrid(origin: Vec3, ids: ndarray, names: list[str])[source]#

The blocks of a cuboid region of the world.

Each block is stored as an index into a list of block names, which keeps large regions small and makes per-block lookups (e.g. colours) cheap.

Variables:
  • origin – the world position of the block at index [0, 0, 0], the lowest (north west bottom) corner of the region

  • ids – integer array of shape (size x, size y, size z), indexed ids[x][y][z] like a mcwb.Cuboid

  • names – the namespaced block id for each index in ids, e.g. "minecraft:stone"

classmethod from_blocks(blocks: Iterable, origin: Vec3) → BlockGrid[source]#

Make a grid from a 3D array of block names or mcwb.Item, indexed [x][y][z], such as the mcwb.Cuboid returned by grab

Parameters:
  • blocks – a nested list or numpy array of blocks

  • origin – the world position of blocks[0][0][0]

property size: Vec3#

the size of the region in blocks (x, y, z)

property end: Vec3#

the world position of the highest (south east top) corner block

property volume: Volume#

the region as a mcwb.Volume

counts(include_air: bool = False) → dict[str, int][source]#

Count the blocks of each type, most common first. A quick way to check that a build contains what it should.

Parameters:

include_air – also count air (and cave air and void air)

to_names() → ndarray[source]#

a 3D numpy array of block names, indexed [x][y][z]

class mciwb.Palette(colours: Mapping[str, tuple[int, int, int] | tuple[int, int, int, int]] | None = None)[source]#

The colours of blocks, see the module documentation for the rules.

Parameters:

colours – colours that take precedence over the defaults, keyed by block name (with or without the minecraft: namespace), as (r, g, b) or (r, g, b, a) with values 0-255

set(name: str, colour: tuple[int, int, int] | tuple[int, int, int, int]) → None[source]#

Set the colour of a block

Parameters:
  • name – the block name, e.g. “minecraft:stone” or “stone”

  • colour – (r, g, b) or (r, g, b, a), values 0-255

colour(name: str) → tuple[int, int, int, int][source]#

The colour of a block

Parameters:

name – the block name, e.g. “minecraft:red_wool”; any block states, e.g. “[facing=north]”, are ignored

Returns:

(r, g, b, a) with values 0-255. a is 0 for blocks that are not drawn, 255 for solid blocks