Minecraft mashups part one

By Russell Barnes. Posted

Use Minecraft with other software, or even have it control the real world…

Minecraft on the Raspberry Pi is a little different to the version you might have played on another computer or games console. As well as there being no creepers to contend with, there’s also the built-in ability to hack and modify Minecraft.

The full article can be found in The MagPi 41

In the past, we’ve shown you some simple ways to interact with Minecraft using Python; however, you can connect up much more than a simple Python script. Whether it’s other software, such as Sonic Pi, controlling the game with hardware like the Sense HAT, or even having Minecraft control things in the real world, there’s a lot more to try out. So get your Raspberry Pi out and let’s mash up some Minecraft!

Minecraft Python API

here are a few ways to program Minecraft on Raspberry Pi, and we’ll be talking about those in the rest of the feature. The most popular way to mod it, however, is by using the included Python library. If you’ve ever used Python, the syntax and logic of the code remains the same, only now there are functions that link directly into Minecraft!

As we’re programming in Python, we can also connect Minecraft to the real world via the GPIO pins or any attached hardware that works with Python, such as the Pi Camera or Sense HAT. Here’s how to get started...

Code: Location
Usage: getPos()
Example: position = mc.player.getPos() will give a list of coordinates for the player’s current position

from mcpi.minecraft import Minecraft
mc = Minecraft.create()
print mc.player.getPos()
Vec3(5.67561,0.0,6.55693)

 Find your position in Minecraft

This returns the player’s position in the world as three numbers. The first number on the X-axis indicates how far forward or back the player is from the centre. The second number is how far left or right they are, or the Y-axis. The last number, the Z-axis, is the height in blocks from ground level.

Code: Teleport
Usage: .setPos(x,y,z)
Example: mc.player.setPos(0.0, 0.0, 0.0) will teleport the player to the centre of the map

mc.player.setPos(10.0,12.0,5.0)
mc.player.setPos(10.0,12.0,-5.0)

 Move to a specific co-ordinate

Using the same coordinate system of X, Y and Z from getPos(), you can move the player around the map as you see fit. You’ll have to figure out the coordinates you want to move to via testing, or by using getPos() at the desired spot.

Code: Block type
Usage: getBlock(x,y,z)
Example: block = mc.
getBlock(0,0,0)
sets variable block as the type of block at the centre of the map

print mc.getBlock(10.0,3.0,-5.0)
3
print mc.getBlock(5,-1,7)
12

 What block is there? Maybe you could look deep into the cliff

Each block type has a name and identification number for it; for example, AIR has the ID of 0. Using the getBlock function, you can figure out what kind of block is at certain coordinates: this is useful for figuring out where a player is in your code if you need to trigger a certain event.

Code: Create a block
Usage: .setBlock(x,y,z,ID)
Example: mc.setBlock(0,0,0, block.OBSIDIAN.id) will create a block of obsidian in the centre of the map

mc.setBlock(10.0,0.0,-1.0, block.OBSIDIAN.id)
mc.setBlock(10.0,0.0,-2.0, block.OBSIDIAN.id)
mc.setBlock(9.0,2.0,-2.0, block.ICE.id)

Create any kind of block wherever you want it in the world. You can see how this works in CrazySqueak’s code next, as he has created lava, water, and empty spaces as part of the Natural Disasters program. You can also create a chunk of blocks with a range of coordinates.

Create natural disaster in Minecraft

I have created natural disasters in Minecraft using Python,” ten-year-old CrazySqueak writes on his blog. “It adds many disasters to your Minecraft that happen randomly, wherever you are in your world. The program randomly starts disasters on its own, so you should keep moving to avoid getting hit.”

This excellent Python script for Minecraft does something very different from other Python hacks that require player interaction: it actually adds to the world in the way a normal PC game mod might. With earthquakes, sinkholes, meteors, geysers, and volcanic eruptions each acting differently and independently, a lot of work has gone into this program.

 An eruption of lava as created by CrazySqueak's code

The code works by setting up the parameters of each disaster. Each type has individual timing for when it occurs, once triggered, and how long it works for. They all use the Minecraft Python API (discussed over the page) to create or remove blocks, such as creating lava for the eruption and meteor, or creating an empty space with the sinkhole and earthquake.

All the disasters are triggered at random in the code, and are based around your location in the game – that’s why CrazySqueak suggests staying on the move! You can also trigger each function individually to see how it works, and some even come with sound clips to further add to the effect of the mod.

As well as creating natural disasters, CrazySqueak received a Highly Commended award for a submission to Astro Pi. We can’t wait to see what other mashups he creates for Minecraft in the future.

Code listing

You can download the full code, along with the accompanying sound clips, from CrazySqueak's website. The code is also below for reference.

import mcpi.minecraft as minc
import mcpi.block as block
mc = minc.Minecraft.create()
import random, time, pygame
pygame.mixer.init()
earthSound = pygame.mixer.Sound('earthquake.ogg')
eruptSound = pygame.mixer.Sound('lava.ogg')
meteorSound = pygame.mixer.Sound('meteor.ogg')
def earthquake(x, z):
    mc.postToChat('Earthquake!')
    y = mc.getHeight(x, z)
    endtime = time.time() + 60
    nearthtime = time.time()
    while endtime > time.time():
        if time.time() > nearthtime:
            earthSound.play()
            nearthtime = time.time() + 5
        ppos = mc.player.getPos()
        if ppos.x < x+15 and ppos.x > x-15:
            if ppos.y < y+15 and ppos.y > -60:
                if ppos.z < z+15 and ppos.z > z-15:
                    mc.player.setPos(ppos.x, ppos.y, ppos.z)
        bx = random.randint(x-15, x+15)
        by = y
        bz = random.randint(z-15, z+15)
        if mc.getHeight(bx, bz) > -50:
            by = mc.getHeight(bx, bz)
        if mc.getBlock(bx, by, bz) in [block.GLASS.id, block.GLASS_PANE.id]:
            mc.setBlock(bx, by, bz, block.AIR.id)
            continue
        mc.setBlock(bx, by, bz, block.GRAVEL.id)
        mc.setBlocks(bx, by-1, bz, bx, -60, bz, block.AIR.id)
def sinkhole(x, z):
    blks = []
    y = mc.getHeight(x, z)
    xdist = random.randint(1, 5)
    for bx in range(-xdist, xdist+1):
        zdist = random.randint(1, 5)
        for bz in range(-zdist, zdist+1):
            blks.append([x+bx, z+bz])
    earthSound.play()
    for blk in blks:
        mc.setBlocks(blk[0], mc.getHeight(blk[0], blk[1]), blk[1], blk[0], -60, blk[1], block.AIR.id)
        mc.setBlocks(blk[0], -55, blk[1], blk[0], -60, blk[1], block.LAVA.id)
    for blk in blks:
        mc.setBlock(blk[0], y, blk[1], block.GRAVEL.id)
def geyser(x, z):
    y = mc.getHeight(x, z)
    mc.setBlocks(x-2, y+5, z-2, x+2, -60, z+2, block.WATER.id)
    time.sleep(25)
    mc.setBlocks(x-2, y+5, z-2, x+2, -60, z+2, block.AIR.id)
def eruption(x, z):
    y = mc.getHeight(x, z)
    for i in range(3):
        eruptSound.play()
        mc.setBlocks(x-2, y+9, z-2, x+2, y+9, z+2, block.LAVA.id)
        eruptSound.play()
        for i in range(15):
            time.sleep(1)
            eruptSound.play()
        eruptSound.play()
        mc.setBlocks(x-2, y+10, z-2, x+2, y+10, z+2, block.WATER.id)
        eruptSound.play()
        for i in range(5):
            time.sleep(1)
            eruptSound.play()
        eruptSound.play()
        mc.setBlocks(x-2, y+10, z-2, x+2, y+10, z+2, block.AIR.id)
        eruptSound.play()
        for i in range(5):
            time.sleep(1)
            eruptSound.play()
        eruptSound.play()
        y += 1
        eruptSound.play()
def meteor(x, z):
    mc.postToChat('Meteor approaching!')
    y = 64
    h = mc.getHeight(x, z)
    x -= (64 - h)
    meteorSound.play()
    while y > h:
        y -= 1
        x += 1
        mc.setBlocks(x-2, y-2, z-2, x+2, y+2, z+2, block.OBSIDIAN.id)
        time.sleep(0.05)
        mc.setBlocks(x-2, y-2, z-2, x+2, y+2, z+2, block.AIR.id)
    mc.setBlocks(x-2, y-2, z-2, x+2, y+2, z+2, block.LAVA.id)
    mc.setBlocks(x-1, y-1, z-1, x+1, y+1, z+1, block.OBSIDIAN.id)
def meteor_shower(x, z):
    for i in range(10):
        mx = random.randint(x-15, x+15)
        mz = random.randint(z-15, z+15)
        meteor(mx, mz)
def heatwave(x, z):
    y = mc.getHeight(x, z)
    endtime = time.time() + random.randint(50, 90)
    while time.time() < endtime:
        blkid = block.AIR.id
        while blkid == block.AIR.id:
            bx = random.randint(x-10, x+10)
            by = random.randint(y, y+10)
            bz = random.randint(z-10, z+10)
            blkid = mc.getBlockWithData(bx, by, bz).id
        blk = blkid
        blkd = mc.getBlockWithData(bx, by, bz).data
        if blkid == block.GRASS.id:
            blk = block.DIRT.id
            blkd = 0
        elif blkid in [block.WATER.id, block.WATER_FLOWING.id, block.WATER_STATIONARY.id]:
            blk = block.WATER.id
            blkd = 1
        elif blkid == block.LEAVES.id:
            blk = block.COBWEB.id
            blkd = 0
        elif blkid == block.WOOD.id:
            blk = block.LAVA_STATIONARY.id
            blkd = 1
        mc.setBlock(bx, by, bz, blk, blkd)
def tsunami(x, z):
    tend = time.time() + 15
    tx = x
    while time.time() < tend:
        h = mc.getHeight(tx, z)
        mc.setBlocks(tx, h-5, z-5, tx, h+5, z+5, block.WATER_STATIONARY.id)
        time.sleep(0.1)
        mc.setBlocks(tx, h-5, z-5, tx, h+5, z+5, block.AIR.id)
        time.sleep(0.1)
        tx += 1
    hm = 5
    while hm > -1:
        h = mc.getHeight(tx, z)
        mc.setBlocks(tx, h-int(hm), z-5, tx, h+int(hm), z+5, block.WATER_STATIONARY.id)
        time.sleep(0.1)
        mc.setBlocks(tx, h-int(hm), z-5, tx, h+int(hm), z+5, block.AIR.id)
        time.sleep(0.1)
        tx += 1
        hm -= 0.2
disasters = [tsunami, heatwave, meteor, meteor_shower, geyser, earthquake, sinkhole]
def main(disasters, mc):
    baseed = random.randint(1, 10000)
    while True:
        t = random.randint(15, 180)
        t = 15
        time.sleep(t)
        random.seed(baseed + t)
        baseed = random.randint(1, 10000)
        random.shuffle(disasters)
        disaster = random.choice(disasters)
        ppos = mc.player.getTilePos()
        #mc.postToChat(str(disaster) + ' in')
        #for c in range(3, 0, -1):
        #    mc.postToChat(str(c))
        #    time.sleep(0.33)
        disaster(ppos.x, ppos.z)
try:
    import _thread as thread
except ImportError:
    import thread
thread.start_new_thread(main, (disasters, mc))

Carry on to Minecraft Mashups part two.

From The MagPi store

Subscribe

Subscribe to the newsletter

Get every issue delivered directly to your inbox and keep up to date with the latest news, offers, events, and more.