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)
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.
#!/bin/sh
BINDIR=$(dirname "$(readlink -fn "$0")")
cd "$BINDIR"/Minecraft
java -Xms1024M -Xmx1024M -jar craftbukkit.jar -o true
#!/bin/sh
BINDIR=$(dirname "$(readlink -fn "$0")")
java -Xms1024M -Xmx1024M -jar ${BINDIR}/Minecraft/minecraft.jar -o true
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!
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 |
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");
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!