Syntax
Inline Function Definition
In the early versions of Subfunctions, the filter was exclusively used to define functions within functions (hence the name “Subfunctions”). There are three ways to achieve this: using the definefunction keyword, the function keyword, or the schedule keyword. All of them create a new .mcfunction file, but with distinctions: function instantly calls the function inside the file containing it, schedule schedules the function, and definefunction only creates the file.
function - Subfunctions defined and executed instantly
Syntax
[any_code] function <[function_name]>:
[function_body]
- any_code: usually an execute command, but since subfunctions don't parse
mcfunction files, you can put there any string.
- function_name: the name of the new function to create that follows the
pattern: [A-Za-z0-9_]+. The file is created inside a folder with the same
name as the root function.
- function_body: multiline body of the function. The body ends with the line
that doesn't have enough indentation (similar to Python).
Description
The function command has an extended syntax. You can use the function keyword combined with a subfunction name between < and > symbols. It creates a subfolder with the same name as the root function and the subfunction inside it named after the provided name.
Inside the root function, the code of the subfunction is replaced with a subfunction call. The filter accepts any code that isn’t a comment and that ends with function <subfunction name>:. The subfunction must use symbols valid for the function name.
Example
BP/functions/xxx/yyy/zzz.mcfunction
# Some code
function <aaa>:
# The code of the subfunction
execute @a ~ ~ ~ function <bbb>:
# The code of the nested subfunction
# Some other code
The file above would resolve into: BP/functions/xxx/yyy/zzz.mcfunction
# Some code
function xxx/yyy/zzz/aaa
# Some other code
BP/functions/xxx/yyy/zzz/aaa.mcfunction
execute @a ~ ~ ~ function xxx/yyy/zzz/aaa/bbb
BP/functions/xxx/yyy/zzz/aaa/bbb.mcfunction
# The code of the nested subfunction
definefunction - Definition of a subfunction without execution
Syntax
definefunction <[function_name]>:
[function_body]
- function_name: the name of the new function to create that follows the
pattern:[A-Za-z0-9_]+. The file is created inside a folder with the same name
as the root function.
- function_body: multiline body of the function. The body ends
with the line that doesn't have enough indentation (similar to Python).
Description
Subfunction definitions can be created using the definefunction <subfunction name>: pattern. You can’t combine definefunction with any other commands (like execute). The definefunction line must start with the definefunction keyword or with indentation.
schedule - Subfunctions defined in a schedule command
Syntax
[any_code] schedule [any_schedule_options] <[function_name]>:
[function_body]
- any_code: usually an execute command or chain of execute commands, but since
subfunctions don't parse mcfunction files, you can put any string here.
- any_schedule_options: any options valid for the schedule command (anything
that goes after the 'schedule' keyword and before the function name).
- function_name: the name of the new function to create that follows the
pattern: [A-Za-z0-9]+. The file is created inside a folder with the same name
as the root function.
- function_body: multiline body of the function. The body ends with the line
that doesn't have enough indentation (similar to Python).
Description
The schedule command can be used to create subfunctions in the same way as the function command. If you put the function name between < and > symbols, it creates a subfolder with the same name as the root function and the subfunction in it named after the provided name.
Inside the root function, the code of the subfunction is replaced with a subfunction call (using the schedule command).
Example
BP/functions/xxx/yyy/zzz.mcfunction
# Some code
schedule on_area_loaded 1 2 3 11 22 33 <aaa>:
# The code of the subfunction
The file above would resolve into: BP/functions/xxx/yyy/zzz.mcfunction
# Some code
schedule on_area_loaded 1 2 3 11 22 33 xxx/yyy/zzz/aaa
BP/functions/xxx/yyy/zzz/aaa.mcfunction
# The code of the subfunction
Calling subfunctions from definefunction and function
Since the pattern of creating the subfunction names is known, you can call them like any other function.
Function Trees
Function trees are binary structures that allow you to run Minecraft commands based on a scoreboard value. Since the introduction of the Scripting API into Minecraft they are not as useful as they used to be, but if you prefer to use function based workflow, they provide a performant way of converting scoreboard values into commands.
Note
Function trees generate a lot of files; each step in the search tree is a separate file. Searching through large ranges of values (more than a few hundred) is not recommended.
functiontree - a binary tree of functions
Syntax
functiontree <[function_name]><[selector] [scoreboard] [start]..[stop]>:
[function_body]
- function_name: a base name of the new functions to create (must follow the
pattern [A-Za-z0-9_]+), the files are created inside a folder with the same
name as the root function and are named after function_name with the addition
of a suffix that represents
the scoreboard range they search.
- selector: the selector or a fake player name used for generating execute
commands.
- scoreboard: the name of the scoreboard used for function tree.
- start: the starting value of the range.
- stop: the end value of the range.
- step: the incrementation step (optional).
- function_body: multiline body of the function. The body ends
with the line that doesn't have enough indentation (like in the Python
programming language).
Description
functiontree allows you to quickly search values of a scoreboard for selector using a binary tree made out of function files calling each other. It also adds a variable to the scope named after the scoreboard. The value of the variable is the same as the value of the scoreboard at the moment of calling the function. It can be accessed using eval (see documentation below).
Example
This is an example of a simple implementation of getting elements from a table created from 100 scoreboards that uses tab_index scoreboard to point at the index of the table to be accessed and table_io to copy the value from the table.
Source: BP/functions/table.mcfunction
functiontree <table_get><@s tab_index 0..100>:
scoreboard players operation @s table_io = @s t_`eval:tab_index`
Compiled code: BP/functions/table.mcfunction
execute if score @s tab_index matches 0..49 run function table/get_0_49
execute if score @s tab_index matches 50..99 run function table/get_50_99
Example branch: BP/functions/table/get_0_49.mcfunction
execute if score @s tab_index matches 0..24 run function table/get_0_24
execute if score @s tab_index matches 25..49 run function table/get_25_49
Example leaf: BP/functions/table/get_1_2.mcfunction
execute if score @s tab_index matches 1..1 run scoreboard players operation @s table_io = @s t_1
execute if score @s tab_index matches 2..2 run scoreboard players operation @s table_io = @s t_2
Variables and Code Evaluation
Subfunctions can define variables and use them in Python expressions whose value is evaluated and inserted into the function code. If you’re using Subfunctions as a module of System Template, all of the variables defined in all of the scopes are available. If you’re using Subfunctions as an independent filter, you can define variables in the scope file, whose path is defined in the filter configuration.
var - defining variables for later use in the same function
Syntax
var [identifier] = [expression]
- identifier: the name of the variable.
- expression: expression whose value is assigned to the variable.
Example
var pi = 3.14
> - evaluating expression without assigning it to a variable
Description
This is almost the same as var but there is no variable to add to the scope. This is useful for modifying existing variables (for example expanding lists).
Syntax
> [expression]
- expression: the expression to be evaluated.
Example
> my_list.append(2)
eval - static code generation based on simple expressions
Syntax
`eval:[math_expression]`
- math_expression: the expression to be evaluated and inserted instead to
the function of eval.
Description
Eval is used to generate code based on basic math expressions. It can also access the variables from for and functiontree.
Loops
Writing Mcfunction code often requires repeating the same or very similar code multiple times. To make it easier, subfunctions provide a few ways to generate code in a loop.
for - generating code in a loop
Syntax
for <[variable] [start]..[stop] [step]>:
[body]
- variable: the variable used in the for loop added to the scope for `eval`.
- start: starting value of range.
- stop: end value of range.
- step: the incrementation step (optional).
- body: multiline body of the for block. The body ends
with the line that doesn't have enough indentation (like in Python
programming language).
Example
Source:
for <i 0..25 5>:
say hello `eval:i`*100=`eval:i*100`
Compiled code (added to the same function):
say hello 0*100=0
say hello 5*100=500
say hello 10*100=1000
say hello 15*100=1500
say hello 20*100=2000
foreach - generating code from collections
Syntax
for <[index] [variable] [expression]>:
[body]
- variable: the variable used in the for loop added to the scope for `eval`
- index: a name of the variable used to keep track of the item index in the
collection (starting from index 0). The value is added to the scope and
accessible in `eval`.
- body: multiline body of the for block. The body ends
with the line that doesn't have enough indentation (like in Python
programming language)
Example
Source:
foreach <i animal ["cat", "dog", "parrot"]>:
say `eval:i` `eval:animal`
Compiled code (added to the same function):
say 0 cat
say 1 dog
say 2 parrot
Conditional Statements
Currently, Subfunctions support only one conditional statement - if statement.
if - generating code based on condition
Syntax
if <[expression]>:
[body]
- expression: the expression with a condition that decides whether the body
of the if block should be included in the function.
- body: multiline body of the if block. The body ends with the line that
doesn't have enough indentation (like in the Python programming language)
Description
The if statement executes the body of the block only if the expression evaluates to True. The expression can be any valid Python expression. Currently, the if statement doesn’t support else or else if statements.
Unpacking Functions
Unpacking subfunctions is a feature that allows you to have a single file that doesn’t get converted into a function, but instead, it gets converted into multiple functions defined using the definefunction command. There are two types of unpacking functions: UNPACK:HERE and UNPACK:SUBFUNCTION.
UNPACK:HERE and UNPACK:SUBFUNCTION
Description
UNPACK:HERE and UNPACK:SUBFUNCTION are special annotations that you can put at the first line of the mcfunction file. The files with these annotations are deleted from the pack. They can be used to create multiple function definitions in one place using definefunction. Using function <>: and normal commands in files with these annotations, outside of definefunction code block is not allowed.
UNPACK:HEREunpacks the functions defined withdefinefunctionin the same path as the source file. It ignores the name of the source file.UNPACK:SUBFUNCTIONdoesn’t modify the default behavior ofdefinefunction. It unpacks the functions into a subfolder with the same name as the source file.
Assertions
When writing a complex code in a subfunction, you may want to check if the data is what you expect it to be. For example, you may want to check if a variable is a specific type or if it has a specific value. You can do this using assertions. When your code is dynamically generated based on provided scope, you may want to check if the scope fulfills some conditions. You can do this using assertions.
assert - breaking the execution based on the condition
Syntax
assert [expression]
- expression: the expression which decides whether the execution should
be broken.
Description
The assert checks if the expression is true. If it is not, the execution breaks,and the error is printed in the console. This way, you can catch errors in your code in a predictable way before they cause problems in the generated code (which may be hard to debug). Assertions don’t have any effect on the generated code.
Indentation Rules
In normal mcfunction files, indentation doesn’t matter. Subfunctions use the indentation to group the code in the same way as in Python. As shown in the examples above, the indentation is used to determine the scope of blocks like for, definefunction, functiontree, etc.
Apart from all of these situations, where the indentation has a syntactic meaning, there is one additional case in which the indentation is allowed: You can create indented blocks of code if they have a comment at the top used as a header. Here is an example:
# This is a comment about the block of code
say first command
say second command
say third command
Without the comment or the use of the syntax that requires indented blocks, you can’t use arbitrary indentation:
say This is not allowed!
say This line will create an error!
say second command
say third command
This limitation lets Subfunctions detect errors like typos in the lines that can be used to start an indented block (for example define_function instead of definefunction).
define_function <my_function>:
say Subfunctions would detect an error here!
Comments
A double hash
##is used to comment out the rest of the line. Comments that start with##are not copied to the compiled file, unlike normal mcfunction comments (single hash#).