Friday, July 3, 2015

MCPI-Scratch: Updated to manipulate Minecraft from ScratchX


The MCPI-Scratch application has been changed to work with the new ScratchX editor. The Scratch project has changed how it works with extensions so it was necessary to change MCPI-Scratch accordingly.




The basic setup is still the same. MCPI-Scratch acts as a bridge between ScratchX and Minecraft allowing Scratch blocks to invoke the Minecraft PI API as described in this earlier post



The box labelled "Scratch 2.0 Extension Helper App" is now just MCPI-Scratch python app

The previous version of MCPI-Scratch used the standalone Scratch2 Editor and its mechanism for interacting with external programs - the Scratch Extension Protocol.

ScratchX, in contrast, is a webapp that allows javascript to provide additional functionality. The new version of MCPI-Scratch simply provides a javascript app to connect from ScratchX to the python MCPI-Scratch app. 

The MCPI-Scratch python application interacts with the Minecraft Pi Protocol. That gives flexibility to connect to either a local CraftBukkit server with the RaspberryJuice mod or to Minecraft Pi Edition. We have both setups and its been tested on both of them.

Installation and Getting Started

The app now has a github page with the most up to date details about how to install and get started.

Other than the javascript app and small change to the python application to allow web requests from ScratchX, there are no other changes - so the example applications from previous blog posts will continue to work. I've copied some of the original examples below. Plus there are the Circles and Lines examples.





You should now be ready to write scripts to interact with Minecraft.

Blocks

In the initial release I've only implemented blocks for the following commands
  • postToChat
  • setPlayerPos
  • setBlock: this includes a flag to set the block using absolute coordinates or relative to the player position
  • setBlocks
This is enough to get started. I'll add more blocks to represent the Minecraft Pi Protocol API if people are interested.


There is a good API reference at the StuffAboutCode blog and you can easily adapt the python examples from that blog to Scratch programs


Examples

The installation as a couple of sample scripts

postToChat

The postToChat.sb2 script is a good way to test your set up.

Simply open that file from the scratchExamples directory, click on the script in the Scratch editor, and it should print a hello message in the minecraft chat console.

If this is working then you're ready to try the other blocks.


simpleHouse

The simpleHouse.sb2 script creates a very simple square house using setBlocks block.


It also has some other statements to both clean up and test the other blocks.

rainbow

An adaptation of the rainbow example that is popular in python api tutorials for minecraft
(it took a painfully long time to figure out that the sine function in python and Scratch operate on radians and degrees respectively - fun with debugging...)



That's it. Give it a whirl.

12 comments:

  1. This is a fantastic piece of work - just what I was looking for and hoping not to have to put together from the ground up. A couple of things for completeness sake for the RPi setup (and I am a complete RPi/Linux newbie, so forgive me if my terminology goes astray here and there):

    It seems that no browsers in the Raspbian Jessie repository support flash (and no flash means no scratchx.org, so pretty much a dealbreaker), but you can get an old version of Chromium to run a plugin. I followed the instructions by kusti8 here: https://www.raspberrypi.org/forums/viewtopic.php?t=121195 and it worked perfectly

    BUT...

    You still have to get a flash plugin. The Pepper Flash Player seems to be the favoured choice. I followed gkreidl's instructions here: https://www.raspberrypi.org/forums/viewtopic.php?t=99202

    which also worked perfectly.

    So we're up and running now - my daughter loves MCPI-Scratch, by the way. Typing commands into the python shell was just too much of an ask for a 9 year old.

    Thanks again for all your work, and for sharing it, too. If you're interested, we'll send you an .sbx or two once we're up to speed.

    ReplyDelete
  2. Thanks for the tip. I didn't realise we could get it all working on the RPi using chromium

    ReplyDelete
  3. Well... you can get it working, but it's very laggy. Almost painfully so.

    I might overclock the Pi and see if that helps but I suspect that we will end up using scratch2mcpi on the pi and your extension on the pc. I prefer yours (the other doesn't have setBlocks, just setBlock which makes for alot more grunt work making bigger structures), but this flash craziness on the latest versions of scratch pretty much kills it for the Pi :(

    I'd love to see some more of the API functionality in MCPI-Scratch - being able to get the player position to use as a scratch variable for example, and the getBlock function. I wonder - are these types of functions not included because it's another thing entirely getting the API to talk back to Scratch?

    ReplyDelete
  4. I had those functions in the original api but scratchx has a different way of dealing with callbacks so l dropped them so that l could get a scratchx supported version out the door as quickly as possible.

    I'll look into it again.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. Lucas, I've added a block to return the player position to variables in scratch.
    See playerPos.sbx in the sample projects.
    I'd appreciate it if you can give it a try and let me know if it works as expected. Meanwhile I'll get the getBlock function working again and write up the changes with some sample projects

    ReplyDelete
  7. Hi Jason,
    I was playing around with it, too and just got it going last night. I was going to fork my results on github but my getPos function looks pretty much identical to yours so I may not (would have been nice to see this yesterday, though - I got hung up for a good chunk before I realised that you had to trim the data in the callback).
    I got getBlockId working, though - if I have a chance today I will fork it, but it's pretty simple once you see how it all works and I'm sure it will only take you a couple of minutes.

    One thing I couldn't see is how to cache the position programmatically. So far I've been calling getPos on the three coordinates and storing the results to variables to avoid further API calls, but even that costs 3 calls. I was hoping to be able to make one call, and save the results as a list to be able to refer to later but I think I may be asking too much of scratch there. Can you see a way?


    ReplyDelete
  8. Hi,
    I'll add the getBlock tomorrow. Its pretty simple. But nice to know that you've been through the code and can also add functionality.

    The current solution was simply the quickest solution I came up with, but there are others.

    The call from python to minecraft returns all 3 coords with one call, so it would be easy to cache x,y,z with only one call the mc. But it would be hard to know when to use the cached values and when to fetch new ones.

    An alternative is to continually poll minecraft from the extension (every second for example) and then return the coordinates locally from the extension as needed. This is the approach that is used in the ISS example (http://khanning.github.io/scratch-isstracker-extension/).

    I could implement this easily enough but I'm not sure what the benefit is. Its not that time intensive to call to the local minecraft server. And polling would be more intensive for minecraft.

    Do you have a scenario where it would be useful to constantly poll minecraft rather than fetching the coords each time?

    J

    ReplyDelete
  9. I can see how you would return x,y,z to the JavaScript in one hit, what I can't see is how you would cache those in Scratch in any meaningful way to refer to later.
    With the old Scratch extensions, it seems that you could create variables programatically. What I imagine would be useful would be one block labelled "update Player pos" which when run would update three data variables that the extension had already created - playerX, playerY and playerZ. That way you would only need to call the API if you knew (or suspected) the position had changed.

    But I can't see a way to either pre-define variables (although I guess these would be other "More Blocks") or get the .js to update other blocks that did not call the function themselves. Maybe I'm looking at it wrong.

    The only scenario I can think of for constant polling would be something like the stuffaboutcode example (http://www.stuffaboutcode.com/2013/02/raspberry-pi-minecraft-auto-bridge.html) which just runs on a while(True): loop anyway which would be I guess the equivalent of a "Forever" block in Scratch.

    I think it could be handy for building things just by walking around - you could construct mazes that way, or more complicated wall structures or minecart rails without having to make a whole bunch of setBlocks calls. But then really that is moving away from "teaching kids to code" and getting more into game modding.

    I have one small suggestion - for our purposes the floats returned by player.getPos() are too much detail. You can save having to round them back to integers by calling player.getTilePos()

    ReplyDelete
  10. Never mind - I think I figured it out. Cache the values in the js, set them with the R block and get them with r blocks. Silly me...

    ReplyDelete
  11. That approach to caching is the one I mentioned from the ISS example. But it still doesn't solve the problem - how do you know when to use the cache and when to refresh the values from mc.

    Is there a performance problem for you to fetch them from mc each time?

    Thanks for the getTilePos tip. I didn't know about that

    ReplyDelete
  12. Lucas, getBlock is now working. At least for the blockType at a particular position. I haven't returned the block data (yet).
    To try out polling I added a hat block to detect block hits. If you hit a block with a sword it will trigger the block in Scratch. It polls minecraft every 2 secs and returns a boolean if something was hit in that period.
    (Based on the stuffaboutcode example: http://www.stuffaboutcode.com/2013/05/raspberry-pi-minecraft-block-events.html)

    Its worked a few times but I'm struggling to get it to work reliably. But you can try it out while I debug it.

    ReplyDelete