Code : ScriptCraft : Golden Hoe of Impatience

When I'm playing Minecraft with my kids, we have a tendency to end up with large farms: Large farm

It easily gets tedious when we harvest everything and then plant the seeds back properly on each dirt block. This is where ScriptCraft is useful. It has an API for doing lots of interesting things in a Bukkit based Minecraft server, but it can also be used to modify or extend existing tools.

To make farming quicker (so we could spend more time on other things), I modified the gold hoe using ScriptCraft. By adding some JavaScript code (I'll show this in a bit), we're able to harvest and re-plant a 3 by 3 square of wheat, carrots or potatoes by right-clicking the centre block with a golden hoe: Farming and auto-planting a 3x3 square of wheat

I also implemented a slight cheat feature in it ("supergrow") to grow melon and pumpkin seeds into stalks quickly. It was mainly done out of curiosity, but it turned out to be useful when we experimented with another farming mod. Simply plant a seed and right-click using the golden hoe. The stalk will grow instantly.

New melon seed planted Melon stalk grown

Implementing the golden hoe

To implement this, we first need to install ScriptCraft. There are detailed instructions available on the ScriptCraft homepage, but to summarise it's fairly simple: a) download the ScriptCraft jar file and b) copy it to the bukkit plugins-directory.

The source code for my gold hoe mod is as follows (you can also download it as farming_goldhoe.js). I'll explain the code underneath it, but the main functionality is as follows:

In other words, it will only plant seeds, carrots, potatoes or nether warts in blocks that already have fully grown items of the same type.

// Looks like bukkit only provides a getData() and setData() interface to plant growth. 
// 7 is grown and 0 is newly planted. 
var growable = { 
    141 : true,    // carrot
    142 : true,    // potato
    59 : true      // wheat
}; 

// typeIDs for stalk blocks that the hoe can supergrow. 
// A grown melon has ID 103. Grown pumpkin is 86. 
var stalks = {
    104 : true,   // Pumpkin stalk
    105 : true    // Melon stalk
}; 

// Golden hoe of impatience. 
// it also auto-grows certain seeds/stalks if you click them directly. 
events.on("player.PlayerInteractEvent",function(event) 
{
    var player = event.player; 
    var heldId = player.getItemInHand().getType().getId();

    if (heldId != 294) {  
        // Abort if not a golden hoe
        return ; 
    }
    var block = player.getTargetBlock(null, 5);
    var world = player.getWorld(); 
    var loc  = block.location; 

    // Grows stalks to mature state. 
    if (stalks[block.typeId]) {
        block.data = 7; 
        return; 
    }

    // Go for a 3x3 area around the target block (same height) and break any 
    // grown wheat etc. 
    var dx, dz; 
    for (dx = -1; dx < 2; dx++) {
        for (dz = -1; dz < 2; dz++) {
            var b = world.getBlockAt(loc.getX()+dx, loc.getY(), loc.getZ()+dz);
            if (growable[b.typeId] && b.data == 7) {
                // farm fully grown growable blocks (wheat etc) and replace seeds. 
                var seedID = b.typeId; 
                b.breakNaturally(); 
                b.typeId = seedID; 
                b.data = 0; 
            }
            if (block.typeId == 115 && b.data == 3) {
                // Farms nether warts and re-plants. 
                var seedID = b.typeId; 
                b.breakNaturally(); 
                b.typeId = seedID; 
                b.data = 0; 
            }
        }
    }
}); 

The following is a brief explanation of the above code:

Lines Explanation
3-14 This is a little trick. I'm making two JavaScript objects, but I'm using them as tables of regcognised block types. One (growable) is a table of recognised seeds etc. The other (stalk) is a table of known stalks that can be super/instagrown.
18 Whenever certain things happen in Minecraft, Bukkit sends an event to all registered event handlers. This line registers our function / event handler so that when a player clicks on something, the following function is called.
20-26 We first need to figure out if we're actually holding a golden hoe. If not, just jump back out of the function.
27-29 Get hold of the block the user is pointing at, which world we're in and location of the block
31-35 We're using the table from above to check if this is a stalk if a known type. If it is, we're setting the data value of the block to 7. This represents a fully grown stalk. Values less than 7 represents a stalk that is growing.
39-58 We're examining a 3x3 area around (and including) the block that the user pointed at.
42 Get the currently examined block. world.getBlockAt takes an x,y,z position and returns a block object.
43-49 If it's a "growable" block (checked by looking up in the growable table) and it's fully grown (data is 7), we first save the block type (seedID) and break the block to get the finished product. Then we plant a new seed by setting the typeId and data of the block. The data value is set to 0 to make it a newly planted seed.
50-56 This is similar to the above code, only that it handles nether warts. The main difference is that nether warts are fully grown with a data value of 3.

The code can be simplified even further. Can you do it? ;-)


- John Markus Bjørndalen