I haven't played much Minecraft these days, but enjoy pulling it up from time to time. However, I just recently found an interesting plugin for the game hit my news feeds that goes off the deep end and embeds a full JavaScript execution engine (Rhino) into the game server.

Couldn't resist trying it out myself, wonder what kind of cool creations I'll be able to make with this! For anyone else interested in setting it up here are the required steps (as of today)

1. Download the Following

2. Installation

Being a linux lover, I'll outline how I setup everything for Linux here. There will probably be some differences for your OS - hunt around on the various sites for answers if you wish to setup in a different OS.

  1. Create a folder called bin in your home directory (alternatively for a more centralized installation choose somewhere appropriate in /opt or /usr)
  2. Add ~/bin to your path: in your .bash_profile add "export PATH=$PATH:~/bin"
  3. Create ~/bin/Minecraft
  4. Copy minecraft.jar into the Minecraft folder
  5. Copy craftbukkit-{version}.jar into the Minecraft folder
  6. Symlink craftbukkit.jar to craftbukkit-{version}.jar (ln -s)
  7. Create a shell script called bukkit in bin with the following contents:
    
    #!/bin/sh
    BINDIR=$(dirname "$(readlink -fn "$0")")
    cd "$BINDIR"/Minecraft
    java -Xms1024M -Xmx1024M -jar craftbukkit.jar -o true
    
  8. Create a shell script called minecraft in bin with the following contents:
    
    #!/bin/sh
    BINDIR=$(dirname "$(readlink -fn "$0")")
    java -Xms1024M -Xmx1024M -jar ${BINDIR}/Minecraft/minecraft.jar -o true
    
  9. Execute bukkit, this will generate a fresh world and make a bunch of configuration files available in your Minecraft folder
  10. Edit ops.txt to include your username
  11. Edit server.properties to fit your liking, I prefer a creative environment when playing around with ScriptCraft
  12. Copy scriptcraft into the Minecraft/plugins folder
  13. Restart bukkit
  14. Run minecraft and add localhost as a server

Congratulations you now (hopefully) have a working ScriptCraft installation!

Optionally, you may wish to create a symlink from a creations folder in the Minecraft folder to a creations folder in your home directory. The Minecraft process does not respect your current working directory from which it is launched. I like to place my javascript files for scriptcraft to be loaded in this creations folder. Alternatively, I hear it is possible to decompile the source minecraft.jar and recompile a custom build to fix this behavior, but this simple hack gets the job done!

3. Playing With ScriptCraft

All ScriptCraft commands are accessed with /js in game

As can be seen in github (commit a002e11) ScriptCraft makes the following commands available:

Function Description
load(file) File must be relative to minecraft's working directory, as of today Minecraft forces this to always be the location of minecraft.jar (see optional creations folder above)
getPlayerPos() Returns the player's x,y,z and yaw (direction)
getMousePos() Returns the x,y,z of the current block being targeted.
getMousePos() Returns the x,y,z of the current block being targeted.
putBlock(x, y, z, blockId, metadata) Puts a block at a location in current world
getBlock(x, y, z) Gets the block and metadata (returned as a string in form '35:15')
putSign(texts, x, y, z, blockId, metadata) Puts a sign at the given location
notifyAdministrators(msg) Sends a message to all admins/ops.
echo(msg) Prints a message on screen to current user.

There is also a convenience API called drone, that constructs an invisble construction reference and constructs things from a player's point of view.

Furthermore, each method returns itself. This means we can chain together methods like box(5).up(1).right(4).box(2)

For directions:


	0 = east
	1 = south
	2 = west
	3 = north
Function Description
Drone() (constructor) The drone is created at the crossairs, or 2 blocks ahead of the player if not looking at anything. Building always happens right and front of the dron's position.
Drone(x, y, z, direction) creates a drone at the location and direction specified.
up/down/left/right/fwd/back(n) Move up/down/left/right/fwd/back - n is the number you want to move (default 1)
turn(n) Change direction, always turns right (clockwise)
chkpt(checkpoint_name) String marker for current location
move(checkpoint_name) Go back to previously marked location
box(block, width, height, depth) block = block id
Create a solid box
box0(block, width, height, depth) like box but empties out the inside - ideal for buildings.
prism(block, width, depth) Create a triangular prism
prism0(block, width, depth) Create a prism with an empty inside
cylinder(block, radius, height) Create a cylinder - building begins radius blocks to the right and forward.
cylinder0(block, radius, height) Create an empty cylinder
door(b) Create a door - if a parameter is supplied an Iron door is created otherwise a wooden door is created.
door2(b) Create double doors (left and right side)
sign(s, b) Signs must use block 63 (stand-alone signs) or 68 (signs on walls)
s can be a string or an array of strings.
oak/spruce/birch/jungle() Create trees
rand(distribution, w, h, d) Best shown by example:
rand([98,'98:1','98:2'],w,d,h) will place random blocks stone, mossy stone and cracked stone (each block has the same chance of being picked)
rand({98: 5, '98:1': 3,'98:2': 2},w,d,h) will place random blocks stone has a 50% chance of being picked, mossy stone has a 30% chance and cracked stone has just a 20% chance of being picked.
garden(w, d) Places random flowers and long grass (similar to the effect of placing bonemeal on grass)
copy(name, w, h, d) Copy an area so it can be pasted elsewhere. The name can be used for pasting the copied area elsewhere... drone.copy('somethingCool',10,5,10).right(12).paste('somethingCool'); ... copies a 10x5x10 area (using the drone's coordinates as the starting point) into memory. the copied area can be referenced using the name 'somethingCool'. The drone moves 12 blocks right then pastes the copy.
paste(name) Paste the copied blocks

4. Examples

There are already several examples of how to use ScriptCraft sitting in src/main/javascript. What's really neat is the Java runtime is still accessible within scriptcraft. This allows us to do pretty much anythign we could do in a client java application. dancefloor.js demonstrates a good use of using Java threads to animate blocks. I haven't done much with scriptcraft yet aside from create a simple chessboard routine:


Drone.extend("chessboard", function(white, black, width, depth) {
  this.chkpt('chessboard01232013');
  
  for(var i = 0; i < width; ++i) {
    for(var j = 0; j < depth; ++j) {
      var block = black;
      if((i+j)%2==1) {
        block = white;
      }   
      this.box(block);
      this.right(1);
    }   
    this.move('chessboard01232013').fwd(i+1);
  }

  return this.move('chessboard01232013');
});
echo("Chessboard loaded");
Chessboard

That about sums it up for ScriptCraft, I'll be sure to post some screenshots and code in the future if I get around to making anything interesting!