Friday, 1 February 2013

Raspberry Pi - Minecraft - Auto Bridge

How about if you could wander around the Minecraft world and never fall off a cliff or have to swim across an ocean.  What if, no matter where you walked a bridge automatically appeared under your feet...  Well with Minecraft Pi edition, its API and a small python program, you can have just that!

The code is relatively simple, the program continually monitors the position of the player and by understanding where the player is and where they were, you can predict where they are going to be, if the block they are going to be standing on is empty (or AIR), fill it in!


This is based on the version 0.1.1 of Minecraft: Pi edition, see this post for info on how to install.

Download and run
You can download the code direct from git-hub, so run minecraft, open/create a world and follow the instructions:

sudo apt-get install git-core
cd ~
git clone https://github.com/martinohanlon/minecraft-bridge.git
cd minecraft-bridge
python minecraft-bridge.py

The Code
If you want to have a go yourself, here's the code.

Create a directory for the program

mkdir ~/minecraft-bridge

Copy the python api class library from minecraft to the programs directory

cp -r ~/mcpi/api/python/mcpi ~/minecraft-bridge/minecraft

Create minecraft-bridge.py python program

nano ~/minecraft-bridge/minecraft-bridge.py

or open Idle and save minecraft-bridge.py to the minecraft-bridge directory

Code
Be careful cutting and pasting direct from the web browser, its really easy to get odd characters in the code which will give you syntax errors.

#www.stuffaboutcode.com
#Raspberry Pi, Minecraft - auto bridge

#import the minecraft.py module from the minecraft directory
import minecraft.minecraft as minecraft
#import minecraft block module
import minecraft.block as block
#import time, so delays can be used
import time

#function to round players float position to integer position
def roundVec3(vec3):
    return minecraft.Vec3(int(vec3.x), int(vec3.y), int(vec3.z))

if __name__ == "__main__":

    time.sleep(2)

    #Connect to minecraft by creating the minecraft object
    # - minecraft needs to be running and in a game
    mc = minecraft.Minecraft.create()

    #Post a message to the minecraft chat window
    mc.postToChat("Hi, Minecraft - Auto Bridge Active")
    mc.postToChat("www.stuffaboutcode.com")

    #Get the players position
    lastPlayerPos = mc.player.getPos()

    while (True):

        #Get the players position
        playerPos = mc.player.getPos()

        #Find the difference between the player's position and the last position
        movementX = lastPlayerPos.x - playerPos.x
        movementZ = lastPlayerPos.z - playerPos.z

        #Has the player moved more than 0.2 in any horizontal (x,z) direction

if ((movementX < -0.2) or (movementX > 0.2) or (movementZ < -0.2) or (movementZ > 0.2)):

            #Project players direction forward to the next square
            nextPlayerPos = playerPos
            # keep adding the movement to the players location till the next block is found
            while ((int(playerPos.x) == int(nextPlayerPos.x)) and (int(playerPos.z) == int(nextPlayerPos.z))):
                nextPlayerPos = minecraft.Vec3(nextPlayerPos.x - movementX, nextPlayerPos.y, nextPlayerPos.z - movementZ)

            #Is the block below the next player pos air, if so fill it in with DIAMOND
            blockBelowPos = roundVec3(nextPlayerPos)
            #to resolve issues with negative positions
            if blockBelowPos.z < 0: blockBelowPos.z = blockBelowPos.z - 1
            if blockBelowPos.x < 0: blockBelowPos.x = blockBelowPos.x - 1
            blockBelowPos.y = blockBelowPos.y - 1
            if mc.getBlock(blockBelowPos) == block.AIR:
                mc.setBlock(blockBelowPos.x, blockBelowPos.y, blockBelowPos.z, block.DIAMOND_BLOCK)

            #Store players last position
            lastPlayerPos = playerPos

        #Delay
        time.sleep(0.01)

The complete code repository is also on githubhttps://github.com/martinohanlon/minecraft-bridge.git

Run 
Note - minecraft must be running and you must be in a game

python ~/minecraft-bridge/minecraft-bridge.py

or if using Idle, click Run Module


27 comments:

  1. Hi Martin,

    I think your Minecraft Pi tutorials are super. I was wondering if I could use one for my video tutorials to get girls coding (youtube.com/geekGurlDiaries)?

    ReplyDelete
    Replies
    1. It would be an honour! Obviously a mention and link, would also be appreciated...

      If you need any help, just give me a shout.

      Delete
  2. Ive just realised this had a bug, so when dealing with negative positions it would do odd things like creating blocks to the right of the players position. It turns out I'm not perfect after all! Although the code has now been fixed, so perhaps I've redeemed myself.

    ReplyDelete
  3. Hi, I just commented on your other post but anyway, do you know how to spawn pigs? I don't know if you can use the setBlock or what.

    ReplyDelete
    Replies
    1. No idea, they might not be supported, i havent seen them wandering about in the game. Hopefully they will appear in an update.

      Delete
  4. Question.
    When I do this it is giving me a syntax error. I have tried this and the clock and it does the same on both. I am trying to get these working for my son and I am a little lost. Thanks

    ReplyDelete
    Replies
    1. Hi,

      What's the syntax error? Is there anything specific?

      Are you by any chance cutting and pasting the code directly from the browser into Idle? I suspect you might be getting some odd characters from the browser, they have a habit of doing that.

      I've modified the post to give some instructions about how to download the code directly from github. This way you can be sure you have the right code.

      Let me know ho you get on.

      Mart

      Delete
  5. Doing it from github worked perfectly. There is a very happy 5 year old.
    Thanks so much

    ReplyDelete
  6. hi martin, can I change the Ice block to TNT block ?
    Thanks. :)

    ReplyDelete
    Replies
    1. Do you mean the block I use to create the Bridge? Its actually Diamond block, not ice.

      If so absolutely you can use any block you want, other than ones affected by gravity I suppose like sand.

      Change the DIAMOND_BLOCK in the code to TNT.

      Delete
  7. Brilliant. This should get a lot of kids hooked in to programming. MC is all about algorithms! I'm hoping to use something like this at our Bring Your Kids to Work Day.

    The biggest problem I'm having in playing MC is knowing what direction I'm facing (and getting disoriented all the time). Do you know of a way to show that in the chat window using the API, like you do for distance in the Hide & Seek?

    I'm also wondering about using the API to create a world map and showing it in a separate screen using PyGame.

    At any rate, thanks for blazing the way on this. Great stuff!

    ReplyDelete
  8. When i try to run the program in run it comes up with this; Failed to execute child process "minecraft-bridge/minecraft-bridge.py" (Permission Denied)

    I've gotten it to run in Terminal but the message pops up in the game and does nothing.

    ReplyDelete
    Replies
    1. I have never experienced a permission denied error before, have you tried the simple stuff like running it with sudo, perhaps you have got some odd permissions.

      When you say you have got it to run in terminal, do you mean that the program is running successfully and you get the "Minecraft Autobridge Active" message in Minecraft? When you say it doesnt do anything, Im guessing you mean when you walk it doesnt automatically create a bridge? Do the program give an error in the terminal window?

      Delete
    2. I've got run to run it but it doesn't say anything or do anything.

      Yeah, it runs in the Terminal and i get the ingame message but the Auto-Bridge doesn't form when i walk off a cliff etc. It doesn't give any error whatsoever.

      Delete
    3. Then I am at a loss Im afraid. Just re-downloaded the code and run it with no problems. Sorry.

      Just to confirm any error would appear in the terminal window not as a message in the game tho.

      Delete
  9. I am not able to successfully complete the "git clone" command (this or any other git clone attempt). When I try, I get:
    git: 'clone https://github.com/martinohanlon/minecraft-bridge.git' is not a git command. See 'git --help'

    Any ideas?

    ReplyDelete
    Replies
    1. Er no. I haven't experienced that before or had anyone else mention it.

      1 thought are you cutting and pasting the command from the browser sometimes you get odd characters. Try typing it if you are.

      Delete
    2. Yes, you solved it. I cut-and-paste, and there was not a real "space" between "clone" and "https". Seems obvious in retrospect. Thank you for taking the time to clue me in!

      Delete
  10. hi there!
    I have made a program similar to this and i thought that you could help. My program does almost the same thing but disassembls the bridge when you walk on grass, but it crashes when it removes the bridge. can you help me? here is the program:


    import mcpi.minecraft as minecraft
    import time
    mc = minecraft.Minecraft.create()
    list = ['e',]
    bridge = 20
    water = (8, 9)
    air = 0
    grass = 2
    i = 1

    listlen = 0

    while True:

    pos = mc.player.getTilePos()
    blockbelow = mc.getBlock(pos.x, pos.y - 1, pos.z)
    if blockbelow == air:
    mc.setBlock(pos.x, pos.y - 1, pos.z, bridge)
    list.append((pos.x, pos.y - 1, pos.z))
    print len(list)
    listlen = len(list)
    elif blockbelow == grass and listlen > 3:
    mc.setBlock(list[i], air)
    del(list[i])
    time.sleep(0.01)
    time.sleep(0.001)

    ReplyDelete
    Replies
    1. the tabs don't work on blogger, but there there

      Delete
    2. Crashes? Is there an error message?

      Delete
    3. this is the error message (tabs don't work so i'll add an '~' to replace them):

      Traceback (most recent call last):
      ~File 'bridge.py', line 25, in
      ~~mc.setBlock(list[i], air)
      IndexError: list index out of range

      Delete
    4. I think I need a way to stop it before it deletes the last block

      Delete
    5. The error is easy to explain, you are trying to find an item in your list which doesnt exist, in this case i, which always seems to be 1, why this is happening is more difficult as i cant understand what trying to do.

      The code to me says, if im standing on grass and i have more than 3 blocks in my list, set block 1 in that list to air and move on. If the block below me is air, create a bridge block and add it to the list.

      If your walking through the air you are going to put LOADS of blocks in your list, say 100, if you start standing on grass you are going to remove blocks from that list until you are no longer standing on grass and which point you stop taking blocks off the list, unless you reach a point where there are only 3 blocks list on the list? Is that right? Comments are always very helpful!

      The first thing i would check is that mc.setBlock is ok with you passing a list as the x,y,z parameters e.g. setBlock(list[i], air) i would expect to see setBlock(x,y,z, air). I dont think this is the route of you issue but it might be hiding the real error.

      Best of luck

      Delete
  11. hi
    slight problem here. after i typed python minecraft-bridge.py it said python: cant open file 'minecraft-bridge.py' : [errno 2] no such file or directory.
    im new to programming and not very good at it. also no luck with copy paste too.
    -Tyler

    ReplyDelete
    Replies
    1. Did the code download properly from github? Does the ~/minecraft-bridge/minecraft-bridge.py file exist?

      Delete