| Crates.io | mcfn |
| lib.rs | mcfn |
| version | 0.0.1 |
| created_at | 2023-11-17 16:27:52.208453+00 |
| updated_at | 2023-11-17 16:27:52.208453+00 |
| description | An mcfunction preprocessor |
| homepage | |
| repository | https://github.com/allay-mc/mcfn |
| max_upload_size | |
| id | 1039221 |
| size | 39,494 |
[!NOTE] This preprocessor is primarily designed for Bedrock Edition and may not work for Java Edition due to its different command syntax.
Instead of inventing an entire new programming language like
mcscript for Java Edition, mcfn extends the
mcfunction format to save repetitive tasks in a more readable way.
mcfn makes use of the execute and scoreboard commands to simulate a runtime
within Minecraft. This allows dynamic conditional programming with several macros.
cargo install -f mcfn
To transpile all *.mcfn files within the functions directory, the following
command can be used.
mcfn functions/**/*.mcfn
Leading spaces from each line in the program is removed in the built file. This allows nesting code in blocks for a better visual view.
#!proc greet
say Hello
say World
#!end
#!! can be written like below as well
#!proc greet
say Hello
say World
#!end
There are two different kinds of comments. A normal comment starts with a hash sign
(#) as usual but must not be followed by a bang (!). They are included in the
built file and can be used wherever full commands can be used. In fact, they can be
used at the end of a command. The other kind of comment starts with a hash sign and
two bangs (#!!). They must be used as a whole line meaning they cannot be appended
to a macro or a command.
withThe with macro preprends each line of the block with its argument.
#!with execute as @a
say Hello
say World
#!end
#!! same as
executa as @a say Hello
execute as @a say World
proc and callThe proc macro creates a procedure. Its content can be called at a later point in
the program any amount of times by using the call macro.
#!proc greet
say Hello
say World
#!end
#!call greet
#!call greet
Unlike most programming languages, procedures are always global, meaning a procedure defined within a different procedure can be called from outside as long as the call is present after the procedure has been defined.
#!call foo
#^^^^^^^^^ error
#!proc foo
#!proc bar
say Hello
say World
#!end
#!end
#!call bar
Procedures cannot have parameters. However you can implements such behaviour as shown below:
scoreboard objectes add _internal dummy
#!proc fizzbuzz
#!if scores @s _arg_a matches 3
#!then
say Hi
#!else
say Hello
#!end
#!end
scoreboard players set @s _arg_a 3
#!call fizzbuzz
scoreboard players reset @s _arg_a
scoreboard players set @s _arg_a 20
#!call fizzbuzz
scoreboard players reset @s _arg_a
logThe log macro prints its value to the console at transpile time whenever it is
reached. This may be useful for debugging.
#!log hi
if, ifn and elseYou can use if to verify a condition is met and ifn to verify the opposite. If multiple if or ifn
macros are chained, then the block is executed when one of the conditions is met.
#!if score @s foo matches 3
#!ifn score @s bar matches 5
#!then
say Hello
say World
#!end
You can also add an else-block which will run if none of the conditions were met.
#!if score @s foo matches 3
#!ifn score @s bar matches 5
#!then
say Hello
say World
#!else
say Bye
say World
#!end
includeYou can include another file relative to the current one by using the include
macro.
#!include path/to/file.in
Note that including mcfn files will not be rendered so you may only use this with
mcfunction programs that do not need to be transpiled initially (in case that step
happens after including the file).
This macro can also be used to include some sort of header for example by creating
a mcfunction program consisting of only comments.
declare and deleteA quick way of creating scores is by using the declare macro. Removing a score is
possible with the delete macro.
#!declare x
#!delete x
The result would be:
scoreboard objectives add x dummy
scoreboard objectives remove x
when and elseIf you have used programming languages like C or Rust before you might be familar with conditional compilation. Conditional compilation allows you to build variable programs depending on configuration settings or the OS for instance.
if cfg!(any(target_os = "windows", target_os = "linux")) {
// do performant stuff
} else if cfg!(any(target_os = "android", target_os = "macos")) {
// do less performant stuff
}
This can be implemented in mcfn in a way as well by using the when macro.
#!when MCFN_TARGET windows
#!when MCFN_TARGET linux
#!then
say Hello
#!else
say Hi
#!end
Such conditions compare a specified environment variable (such as MCFN_TARGET) with
a string (such as windows). The block is rendered when the condition is met and
ignored otherwise (also if the environment variable is not defined). The structure
matches normal conditions with the exception that when
is used instead of if and negated when macros do not exist. Note that when branches
still run log and include macros and validate the blocks. The rendered block will
just be ignored during the tranpilation step.
You can then control the transpilation with bash for example by using this syntax:
MCFN_TARGET="windows" mcfn script.mcfn
The preprocessor language is designed to look good with the mcfunction highlighter
as well so you can use it in your repositories. Both .mcfn and .mcfn.mcfunction
are therefore supported as file extensions.
The score __mcfn_internal_n where n may be any natural number and the "fake player"
name __mcfn_internal are used by mcfn and should not be used within a program or
else it might result in unexpected behaviour.
Add the following ruby script to your script directory and refer to it in allay.toml.
# TODO