Tutorial#
bolt_expressions
provides some psuedo pointers which allow you to interopt between normal minecraft (or bolt) commands and our robust interface for generating expressions. The main endpoints for the logic lay in the specialized Scoreboard
and Data
objects.
Before utilizing bolt_expressions
in a bolt script, make sure you require bolt_expressions
in your beet config:
name: my cool project
author: me (cool person)
data_pack:
load: [src]
require:
- bolt
- bolt_expressions
pipeline:
- mecha
Now, inside a valid bolt script, import from our library.
from bolt_expressions import Scoreboard, Data
my_obj = Scoreboard.objective("my_obj")
my_obj["@s"] += 25
Common Use Cases#
The Scoreboard
and Data
objects provides you a rich API for you to interact within your bolt landscape. Most numerical operations (such as +
, *
, %
) will produce sequential scoreboard operation
commands for you to work with. Longer expressions will benefit from an optimization system which will help shorten the size of the resulting commands. Feel free to use various pointers together, our library will chunk through anything!
math = Scoreboard.objective("math")
player = Data.entity("@s")
CONSTANT = 60 * 60 * 24
math["@s"] *= (entity_id["current_id"] / 200) + CONSTANT
math["@a[sort=random, limit=1]"] = player.Health + (player.SelectedSlot * 9) / 5
Generated Commands
scoreboard players operation $i0 bolt.expr.temp = current_id entity.id
scoreboard players operation $i0 bolt.expr.temp /= $200 bolt.expr.const
scoreboard players add $i0 bolt.expr.temp 86400
scoreboard players operation @s math *= $i0 bolt.expr.temp
execute store result score @a[sort=random, limit=1] math run data get entity @s SelectedSlot 1
scoreboard players operation @a[sort=random, limit=1] math *= $9 bolt.expr.const
scoreboard players operation @a[sort=random, limit=1] math /= $5 bolt.expr.const
execute store result score $i3 bolt.expr.temp run data get entity @s Health 1
scoreboard players operation @a[sort=random, limit=1] math += $i3 bolt.expr.temp
You can also utilize local variables to simplify readability with longer operations. This is due to the unique __rebind__
operator provided only in the bolt
context which allows us provide custom behavior with the =
operation. We also have defined helper functions such as min
and max
, alongside sqrt
and **
(for pow
).
damage = Scoreboard.objective("damage")
input = {
"damage": damage["damage"],
"toughness": damage["toughness"],
"armor": damage["armor"]
}
value = damage["value"]
output = damage["output"]
# This example is split up onto 3 lines to help with readability 📖
# The library will consider this one long expression when optimizing 🔥
atf = (10 * input.armor - (400 * input.armor / (80 + 10 * input.toughness))) # python local variable
maxxed = max((10 * input.armor) / 5, atf) # still local variable
output = value * (250 - (min(200, maxxed))) / 25 # ✨ special behavior | generates commands ✨
Generated Commands
scoreboard players set $i0 bolt.expr.temp 10
scoreboard players operation $i0 bolt.expr.temp *= armor damage
scoreboard players operation $i0 bolt.expr.temp /= $5 bolt.expr.const
scoreboard players set $i2 bolt.expr.temp 10
scoreboard players operation $i2 bolt.expr.temp *= armor damage
scoreboard players set $i3 bolt.expr.temp 400
scoreboard players operation $i3 bolt.expr.temp *= armor damage
scoreboard players set $i4 bolt.expr.temp 10
scoreboard players operation $i4 bolt.expr.temp *= toughness damage
scoreboard players add $i4 bolt.expr.temp 80
scoreboard players operation $i3 bolt.expr.temp /= $i4 bolt.expr.temp
scoreboard players operation $i2 bolt.expr.temp -= $i3 bolt.expr.temp
scoreboard players operation $i0 bolt.expr.temp > $i2 bolt.expr.temp
scoreboard players set $i9 bolt.expr.temp 200
scoreboard players operation $i9 bolt.expr.temp < $i0 bolt.expr.temp
scoreboard players set output damage 250
scoreboard players operation output damage -= $i9 bolt.expr.temp
scoreboard players operation output damage *= value damage
scoreboard players operation output damage /= $25 bolt.expr.const
Advanced Use Cases 🔥#
This library sits very nicely in the bolt
workspace as it can integrate with python functions. This leads naturally to a popular callback pattern which allows you to encapsulate repeated and popular patterns. Here are just a couple of examples to get you inspired ✨!
# ./utils
from bolt_expressions import Scoreboard
import random as py_random
math = Scoreboard.objective("abc.math")
temp = Scoreboard.objective("abc.temp")
_LCG_CONSTANT = 1623164762
def randint(min, max, randomize_output=True):
math["#range"] = (max - min) + 1
math["#lcg"] *= math["#lcg.multiplier"]
math["#lcg"] += _LCG_CONSTANT
math["#output"] = math["#lcg"] % math["#range"] + min
if randomize_output:
output = math[f"#output_{hash((min, max, py_random()))}"]
# This is hacky, you could do this in a if statement.
# a) it just copies the `math["output"]` python reference
# b) it performs `__rebind__` and does a `scoreboard players operation`
output = math["output"]
return output
blocks = [...] # pretend this has every block in the game
# ./client
from ./utils import randint, blocks
choice = randint(0, len(blocks))
for node in generate_tree(blocks):
append function node.parent:
if node.partition(8):
if score f"{choice.scoreholder}" f"{choice.objective}" matches node.range function node.children
else:
if score f"{choice.scoreholder}" f"{choice.objective}" matches node.range setblock ~ ~ ~ node.value
# Note, in the future, you will be able to use `choice` directly with mecha commands
In this example, we wrote a wrapper for a tiny randint
function which will generate random number generation (through a LCG). The beauty of an interface like so is that we don't have to worry about passing in scoreholders as arugments, instead, we just pass in numbers, and the function handles the arguments and outputs for us. This lets us write in a more functional style.
🚧 In Construction 🚧
This section is still in progress. Stay tuned!
If you have any cool examples, please let us know! Just open an issue :)