Skip to main content

Tick targets, and expressions in every particle

Three things this time, and the first one is a command instead of a power.

/tick entity and /tick chunk

Minecraft has had /tick since 1.20.3, and it's the right place for this: it already knows how to slow the world down, and it already tells every client about it. Apoli now hangs two more branches off it.

tick entity @e[type=creeper] freeze
tick entity @e[type=arrow] rate 4
tick chunk ~ ~ radius 64 rate 5
tick chunk 0 0 512 512 query

Every operation the command for the whole server has (query, rate, freeze, unfreeze, step and sprint) works on a selector full of entities or on a patch of chunks. The full syntax is on the Tick command page.

The vanilla branches need permission level 3, which is more than a data pack function gets, so the same tree is also registered as /apoli:tick entity … and /apoli:tick chunk … at Apoli's own level 2. Use that one inside .mcfunction files.

A rate above the server's own still does nothing by itself, because a server can't tick one entity more often than it ticks at all. Raise the whole server with /tick rate 40 and hold everything else down with tick chunk, tick entity or apoli:modify_tick_rate on a dimension target.

Every number on a particle is an expression

count, speed, spread, offset_x, offset_y, offset_z, velocity_x, velocity_y, velocity_z and frequency on apoli:particle and both apoli:spawn_particles actions now take an expression wherever they took a number, and spread takes a single number as shorthand for the same figure on all three axes.

So does every number inside a custom particle: size, lifetime, gravity, friction and the variation fields. Those are worked out on the server, once, at the moment the burst spawns, against the entity that spawned it:

{
    "type": "apoli:particle",
    "particle": {
        "type": "apoli:custom",
        "texture": "example:textures/particle/spark.png",
        "size": "0.1 + resource('example:charge') * 0.02",
        "lifetime": "10 + resource('example:charge')"
    },
    "count": "resource('example:charge')",
    "spread": "0.2 + resource('example:charge') * 0.05",
    "frequency": 2
}

That's one power whose particles grow, multiply and live longer as a resource fills, instead of five powers with a condition each.

roll and roll_speed stay as they were. They run on the client, once per particle, which is what makes "roll": "rUni(0, 360)" give every particle its own angle.

apoli:action_on_mouse_movement on NeoForge

The power reads the camera through a wrapper on Entity.turn. On NeoForge that wrapper was still the older version that only handled cursor speed, so the client never added anything up and the power never fired. It fires now.