-
Notifications
You must be signed in to change notification settings - Fork 0
Templates
Templates allow for data-driven and programmatic code generation.
Caution
Never use templates from other developers without reading their source code.
Certain templates can be calling arbitrary binaries with unrecoverable side-effects.
If a template contains a binary file, then it is best adviced to avoid using it. Always compile it from source yourself!
Define a template by creating a manifest.json file inside of templates/<your_template_id> directory.
| π― Example |
|
|
As the name suggests, it generates files based on a list of definitions.
Use generator type with an optional iterators field.
| π― Example |
// File: templates/my_template/manifest.json
{
"$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
"type": "generator",
"iterators": {
"color": ["red", "green", "blue", "white"],
"material": [
["oak", "oak_planks"],
["spruce", "spruce_planks"],
["stone", "stone_bricks"],
]
}
} |
Iterators are used to create generated definitions. Using the example above, we are able to define %[color]_%[material]_couch.json that will output a couch for every combination of color and material iterators, or %[color]_wool to define wool of every color, etc.
Note
In the example above, iterators.material is an array of arrays, so we can access different elements using %[material.<index>] (defaults to 0).
e.g. %[material.1] would output oak_planks, spruce_planks, etc.
Create .json files inside of definitions/ directory. The file names can optionally use defined iterators. The file name will be available as an %[id] variable.
The contents of that file can contain any keys and values. Each key will be available as a variable for substitution.
| π― Example |
// File: templates/my_template/definitions/my_item.json
{
"key1": "Hello World!",
"recipe": [
{
"id": "bread",
"count": 5
}
]
} |
...
Inline templates are used to extend MCFunction syntax with custom contents/logic/side-effects.
The template must either define a snippet or a program to be executed when called.
Use inline type with an optional arguments field.
| π― Example |
// File: templates/my_template/manifest.json
{
"$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
"type": "inline",
"arguments": [
"name",
"objective",
"range"
]
} |
When specified, forces .mcfunction files to call this template with these space-separated positional arguments. They then become available as %[<argument_name>] as variables.
When ommited, any arguments provided to the template will be provided untouched as the first argument. It is then program's responsibility to split it by space if needed.
Snippets replace the template invocation with the specified code by creating a snippet.mcfunction file.
%[...] variable can be used to insert any nested lines.
| π Input (1/2) |
# File: templates/my_template/snippet.mcfunction
scoreboard players set #%[name] %[objective] 0
function ./_for_%[name]
%[...]
scoreboard players add #%[name] %[objective] 1
execute if score #%[name] %[objective] matches %[range] run function ./_for_%[name] |
| π Input (2/2) |
# File: data/example/function/test.mcfunction
#~>for x my.tmp ..5
#~>for y my.tmp ..10
say 123
say "abc" |
| π¦οΈ Output |
# File: data/example/function/test.mcfunction
scoreboard players set #x my.tmp 0
function ./_for_x
scoreboard players set #y my.tmp 0
function ./_for_y
say 123
say "abc"
scoreboard players add #y my.tmp 1
execute if score #y my.tmp matches ..10 run function ./_for_y
scoreboard players add #x my.tmp 1
execute if score #x my.tmp matches ..5 run function ./_for_x |
Programs are arbitrary executables that generate code. It must be an executable file named call (any extension works).
- Positional arguments are provided as command-line arguments.
- Any nested lines can be read from
stdin. - All generated code should be written into
stdout. - Any errors can be written to
stderr. - Return a non-zero exit code for Vintage to interrupt the build process.
| π Input (1/3) |
// File: templates/my_template/manifest.json
{
"$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
"type": "inline",
"arguments": [
"resource"
]
} |
| π Input (2/3) |
#!/bin/python
# File: templates/my_template/call.py
import sys
resource_arg = sys.argv[1]
if resource_arg == "something wrong":
print("invalid input!", file=sys.stderr)
sys.exit(1)
print(f"function {resource_arg} with storage minecraft:example input")
# Write nested lines without modification
for line in sys.stdin:
print(line, end="") |
| π Input (3/3) |
# File: data/example/function/test.mcfunction
#~>my_template example:path
say 123 |
| π¦οΈ Output |
# File: data/example/function/test.mcfunction
function example:path with storage minecraft:example input
say 123 |
As the name suggests, they collect information from specific files and then generate files based on the collected data.
The template must define a collector program and file generators.
Use collector type with a required patterns field.
| π― Example |
// File: templates/my_template/manifest.json
{
"$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
"type": "collector",
"patterns": [
// match all mcfunction files
"**/*.mcfunction"
]
} |
An array of glob patterns matching output files when they are generated.
Use the example from collector manifest.
Programs are arbitrary executables that collect from code. It must be an executable file named collect (any extension works).
-
The collector executable is only called once per project build.
- Use local variables in your language of choice to store all collected data.
- All incoming files can be read from
stdin.- Each file ends with a null character
\0. -
EOFindicates that there are no more files to collect.
- Each file ends with a null character
- Any errors can be written to
stderr. - Return a non-zero exit code for Vintage to interrupt the build process.
- Once all files are collected, a JSON file must be written to
stdoutwith data that will be passed along to file generators.
| π― Example |
# File: templates/my_template/collect.py
# Example python script that would collect all used translation keys.
import sys, json
en_us = {}
for chunk in sys.stdin.buffer.read().split(b"\0"):
if chunk:
code = chunk.decode("utf-8", errors="replace")
key, value = extract_translation_keys(code) # TODO
en_us[key] = value
json.dump({"en_us": en_us}, sys.stdout) |
There exist 2 types of file generators: generated & programatic.
Programatic generators are arbitrary executables that generate code. It must be an executable file with the name of output file with an executable extension (e.g. en_us.json.py).
- Collected data should be read until
EOFfromstdin. - Any errors can be written to
stderr. - Return a non-zero exit code for Vintage to interrupt the build process.
- Write the output file contents into
stdout.
| π Input |
#!/bin/bash
# File: templates/my_template/assets/minecraft/lang/en_us.json.sh
cat # Simply write the collected data into the file |
| π¦οΈ Output |
// File: assets/minecraft/lang/en_us.json
{
"key1.example": "Hello World!"
} |
Simply runs a custom binary after all codegen, right before managing libraries and zipping the result.
The template must define a custom program.
Use custom type.
| π― Example |
// File: templates/my_template/manifest.json
{
"$schema": "https://bbfh.me/vintage/template_manifest_schema.json",
"type": "custom"
} |
Programs are arbitrary executables that generate code. It must be an executable file named call (any extension works).
- The first argument is the absolute path to build directory (i.e.
--output). - Return a non-zero exit code for Vintage to interrupt the build process.
| π― Example |
# File: templates/my_template/call.py
#!/bin/bash
# Custom templates are always run after the code has finished generating.
# You can freely read/write to the build directory, which you can access from the first argument ($1 for bash).
printf "Build directory is $1!" |
Important
This Wiki is written for a project that does not yet exist.
Vintage is only partially implemented, you must wait until it is production ready.