How to Add Blocks - espertus/blockly-lua GitHub Wiki

Prerequisites

I assume you know:

You must have git and the Java runtime installed to develop for Blockly Lua.

Blockly background

External links

If you like to get the full story, there is very useful information in the Blockly wiki, especially:

You may also find the Block Factory useful.

However, you can get by just by reading this document (when complete).

Expressions vs. statements

One important thing to know is that blocks can either represent expressions or statements. Expression blocks (such as numbers and addition) have a plug on the left side for providing the value, while statement blocks (such as print statements) do not produce a value. Note that statement blocks generally have a notch on top and a bump on bottom to connect to other statements; expression blocks never do.

print statement with add statement plugged into it

Many of the [Turtle API](http://computercraft.info/wiki/Turtle_(API\)) functions, such as Turtle.forward return a boolean value indicating success or failure, which is frequently ignored. Blockly does not provide a way to connect an expression to a program without using its return value, so I put in functionality to convert such blocks between expressions and statements on the context menu, which can be reached by right-clicking. Specifically, the bottom-most option on the expression version (left) is "Remove Output" (not shown), while the statement version (right) has the option "Add Output" (shown).

Expression and statement versions of "move forward"

## Blockly Lua

### Differences from Blockly

Blockly Lua differs from its parent project Blockly by (1) not supporting internationalization, (2) generating Lua code, instead of JavaScript and Python, and (3) only having the code app. In some cases Blockly Lua seems more complicated than necessary because of more general code inherited from Blockly.

### Important directories and files

  • generators/ - Code for translating standard Blockly code (everything not in the ComputerCraft category) to Lua. You shouldn't have to modify this.
  • build.py - This only needs to be run after changes to generators/. You shouldn't have to run this.
  • apps/code/ - Code for the Blockly Lua application.
    • apps/code/blocks.js - Common code used from the following blocks files.
    • apps/code/blocks-turtle.js - Definitions of blocks in the ComputerCraft > Turtle category.
    • apps/code/blocks-os.js - Definitions of blocks in the ComputerCraft > Operating System category.
    • apps/code/template.soy - A Closure template defining the contents of the Blockly Lua application. If you create a new block or category, you will have to add it to this file. After modifying this file, you must run java -jar ../_soy/SoyToJsSrcCompiler.jar --outputPathFormat generated/en.js --srcs ../common.soy,template.soy.
    • apps/code/generated/en.js An auto-generated JavaScript file required by the Blockly Lua application. It must be regenerated whenever template.soy is modified, as described just above.
  • appengine/ - Support for running Blockly Lua on App Engine, something that will be explained later.

## Adding a block to an existing category

You should make all of these changes in a repository of your own forked from the main blockly-lua one.

Create the block

First, find the file to modify. Blocks in the [Turtle API](http://computercraft.info/wiki/Turtle_(API\)) go in apps/code/blocks-turtle.js, blocks in the [OS API](http://computercraft.info/wiki/OS_(API\)) go in apps/code/blocks-os.js, etc.

Next, find a block similar to yours. The following examples are from blocks-turtle.js:

  • If your new block has a simple title (does not contain a dropdown menu), a single input (argument), and no return value, choose turtle_craft.
  • If your new block has a dropdown menu, no inputs, and no return value, choose turtle_turn.
  • If your new block has a dropdown menu, no inputs, and a return value that may be ignored, choose turtle_dig.
  • If your new block has a dropdown menu, no inputs, and a return value that would always be used, choose turtle_detect.

As an example, I will add turtle_attack, which is most similar to turtle_dig. I start by making a copy of the definition of Blockly.Blocks['turtle_dig'], replacing every reference to "dig" with "attack", and rewriting the tooltip text.

Blockly.Blocks['turtle_attack'] = {
  // Block for attacking in front, above, or below the turtle.
  init: function() {
    var DIRECTIONS =
        [['attack in front', 'attack'],
         ['attack up', 'attackUp'],
         ['attack down', 'attackDown']];
    this.setColour(TURTLE_BLOCK_COLOUR_);
    this.appendDummyInput()
        .appendTitle(new Blockly.FieldDropdown(DIRECTIONS), 'DIR');
    this.setOutput(true, 'Boolean');
    this.setTooltip('Try to attack in the specified direction, returning true if successful, false otherwise.');
    var thisBlock = this;
    this.setHelpUrl(function() {
      return BASE_TURTLE_HELP_URL_ + thisBlock.getTitleValue('DIR');
    })
  },
  // Enable block to change between statement and expression.
  changeModes: BlocklyLua.HELPER_FUNCTIONS['changeModes'],
  customContextMenu: BlocklyLua.HELPER_FUNCTIONS['customContextMenu'],
  mutationToDom: BlocklyLua.HELPER_FUNCTIONS['mutationToDom'],
  domToMutation: BlocklyLua.HELPER_FUNCTIONS['domToMutation']
};

Some notes:

  • The local variable DIRECTIONS consists of a list of two-element lists. The first element of each list is the text to show the user. The second element is the name of the corresponding ComputerCraft function. Blockly automagically factors out common text, so "attack" appears on the block, and only "in front", "up", and "down" appear in the dropdown.
  • The second element of the selected dropdown item is referenced as thisBlock.getTitleValue('DIR'). For example, if the user has selected "attack up", the value will be "attackUp". When this is appended to BASE_TURTLE_HELP_URL_ ("http://computercraft.info/wiki/Turtle."), it makes the proper help URL (http://computercraft.info/wiki/Turtle.attackUp).
  • Any single quotes in the tooltip must be preceded with a backslash to avoid ending the tooltip prematurely.
  • The last five lines enable the block to change back and forth between a statement and expression. You can tell that the starting state is expression, because the init() procedure contains a call to this.setOutput(), which is only applicable to expressions.
  • We follow the Google JavaScript style guidelines except that we allow line lengths of greater than 80 characters in the case of strings. The most important meta-rule is to be consistent with existing code.

Create the code generator

As above, copy the code for a similar block (starting Blockly.Lua), replacing the name. In our example, this produces:

Blockly.Lua['turtle_attack'] = function(block) {
  // Generate Lua for attacking forward, up, or down.
  var code = 'turtle.' + block.getTitleValue('DIR') + '()';
  return BlocklyLua.HELPER_FUNCTIONS.generatedCode(block, code);
};

In this case, no further change is needed. As above, if the user has selected "attack up", the expression turtle.attackUp() will be generated. The call to BlocklyLua.HELPER_FUNCTIONS.generatedCode() adjusts it depending on whether the block is in expression or statement mode.

Add to the toolbox

The new block must be added to the XML section of index.html in the appropriate category. As before, copy and modify the definition of a related block.

    <category name="ComputerCraft">
      <category name="Turtle">
        <block type="turtle_move"></block>
        <block type="turtle_turn"></block>
        <block type="turtle_dig"></block>
        <block type="turtle_attack"></block>     <-- New block
          :
      </category>
      :
    </category>

updated toolbox

That was especially simple because the new block doesn't contain any other block.
The XML for the os_sleep block is more complicated because it contains a numeric block initialized to .8 (the amount of time for a block of gravel to fall).

terminate block containing numeric block

<block type="os_sleep">
  <value name="VALUE">
    <block type="math_number">
      <title name="NUM">.8</title>
    </block>
  </value>
</block>

Test Your Block

You can test your new block by loading index.html in a web browser. Open the appropriate category, and you should see your new block. You should use a JavaScript debugger, such as Firebug or the Chrome Developer Tools so you can see any errors. Write a program using your new block. Save the Lua code and XML to pastebin. (The "save" link within Blockly doesn't work when running locally.) Test the Lua program within Minecraft.

Submit a Pull Request

When you are satisfied that your code works and follows the style guidelines, issue a pull request. Include the URLs of the Lua code and XML in an accompanying message.

This is the commit that added turtle_attack.

⚠️ **GitHub.com Fallback** ⚠️