Minecraft Commands - Recursive Functions

663 Views Asked by At

I am making a laser weapon that is basically a function that repeats itself across the 3D world, with each command being executed a block forward in relation to the previous command. However, I found it to be extremely overpowered and decided to nerf it by reducing the effective range of the weapon. I believe that this can be achieved by stopping the recursion at some extend, for example stopping the recursion at the 101th time of it being executed would lead to an effective range of 100 blocks for the weapon.

A part of the code written in raycast.mcfunction

playsound block.iron_trapdoor.open master @a
playsound block.respawn_anchor.deplete master @a
playsound entity.generic.explode master @a
playsound entity.generic.extinguish_fire master @a

particle small_flame ~ ~ ~ 0 0 0 0 100 normal @a
execute if block ~ ~ ~ air unless entity @e[distance=0.1..0.3,type=!armor_stand,type=!item_frame,type=!item,type=!player,type=!area_effect_cloud] positioned ^ ^ ^0.5 run function datapack:raycast

However, I can't quite figure out a way to achieve this, since all variables (scoreboard objectives) in minecraft seems to be available to entities only. A recursive function is not an entity albeit it "moves" in the 3D world.

2

There are 2 best solutions below

1
hfanatic On BEST ANSWER

To solve the problem, recursive functions cannot be employed as they are not treated as entities. I have figured out that by shooting invisble armor stands can I resolve the problem. To summon the armor_stand

execute at @s run summon armor_stand ~ ~ ~ {Invulnerable:1b,Tags:["melta","new_melta"]}

main function

execute as @e[tag=new_melta] at @s rotated as @p run teleport @s ~ ~ ~ ~ ~
execute as @e[tag=new_melta] run tag @s remove new_melta
execute as @e[tag=melta] at @s if block ~ ~ ~ air run tp @s ^ ^ ^1
execute as @e[tag=melta] at @s run summon tnt
execute as @e[tag=melta] at @s unless block ~ ~ ~ air run tag @s add crashed
execute as @e[tag=crashed] run kill @s

The code shown above can be used to shoot an armor stand at where the player is looking, and as it travels tnt would be summoned in its wake. This way we can turn the laser into an entity.

The only drawback is that the laser does not travel at the speed of light, but moves 20 blocks per second (20 ticks = 1 second)

0
Plagiatus On

There is a fairly easy solution to your problem (without sacrificing the speed of the laser as in the accepted answer): Fakeplayers.

While you're right that scores can only be assigned to entities with the usual selectors (@a / @e / etc), you can target players by name directly as well (e.g. /effect give Plagiatus saturation). Thanks to that, you can give scores to players directly, no matter whether they are in the world (or even exist) or not.

See more on how to properly use this to avoid "player collisions" in the link above.


Thus the solution to your issue: Set a score for a fakeplayer (e.g. #steps_remaining) when you start the ray to the amount of steps you want to take (in a dummy objective, e.g. steps), count it down with every step, stop moving forward / the recursion if the score reaches 0.

# start_ray.mcfunction
scoreboard players set #steps_remaining steps 100
function namespace:raycast
#raycast.mcfunction
[...]

scoreboard players remove #steps_remaining steps 1
execute if score #steps_remaining steps matches 1.. if block ~ ~ ~ air unless ...

And thus you basically created a for-loop using only recursion.