5

I read some solutions on the forum at the request of "teleport arrow". It seems like I haven't found the answer to the question I need. If there has already been a similar response, then I apologize.

In general at the moment I have an implementation of a "teleporting arrow" that works using ender pearl. For those who may be interested in the implementation, I am attaching the code below with a description of the functions.

The arrow itself, both in the form of the arrow-entity and in the form of the item-entity, has {data: {arrow_type: "teleport"}}.

Setting the parameters of the launched arrow at HasBeenShot: 0b. The arrow is adjusted so that it can fly through entities without causing damage to them and also so that it cannot be picked up:

execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:0b}] at @s run data modify entity @s PierceLevel set value 10b
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:0b}] at @s run data modify entity @s crit set value 0b
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:0b}] at @s run data modify entity @s damage set value 0.0d
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:0b}] at @s run data modify entity @s pickup set value 0b
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:0b}] at @s run summon minecraft:interaction ~ ~ ~ {Tags:["teleport_arrow_support_interaction"]}

The "interaction" entity is created to save the current value of Motion: [x, y, z] of the arrow (which will be implemented in subsequent commands), so that after the arrow lands, this value of Motion: [x, y, z] can be transferred to ender pearl. This is done because if you don't set ender pearl Motion: [x, y, z] like in arrow, then when the arrow collides with a wall or ceiling, ender pearl will just start falling down, rather than teleporting into that wall or ceiling itself. At the same time the landed arrow has Motion: [0.0d, 0.0d, 0.0d] as a result of which we cannot directly get these values from it for transmission to ender pearl.

Setting the parameters of the flying arrow, i.e. with HasBeenShot: 1b & inGround: 0b:

execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:1b,inGround:0b}] at @s run teleport @n[tag=teleport_arrow_support_interaction] @s
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:1b,inGround:0b}] at @s run data modify entity @n[tag=teleport_arrow_support_interaction] Motion set from entity @s Motion
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},HasBeenShot:1b,inGround:0b}] at @s run particle minecraft:dust{color:[1, 0, 1], scale:2} ~ ~ ~ 0.1 0.1 0.1 1 2 force

As you can see the interaction entity teleports to a flying arrow so that it works correctly with more than one arrow in the world. Particles are also created around the flying arrow.

Setting the parameters of the landed arrow, i.e. with inGround: 1b:

execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run summon minecraft:item ~ ~ ~ {Item: {id: "minecraft:arrow", count: 1}}
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run summon minecraft:ender_pearl ~ ~ ~ {Tags:["teleport_arrow_support_pearl"]}
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run data modify entity @n[type=minecraft:ender_pearl,tag=teleport_arrow_support_pearl] Owner set from entity @s Owner
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run data modify entity @n[type=minecraft:ender_pearl,tag=teleport_arrow_support_pearl] Motion set from entity @n[type=minecraft:interaction,tag=teleport_arrow_support_interaction] Motion
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run kill @n[type=minecraft:interaction,tag=teleport_arrow_support_interaction]
execute as @e[type=minecraft:arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run kill @s

An arrow-item is created near the landed arrow (this function is aimed at survival mode), an ender pearl is also created, to which the parameter Owner: [] is passed from the arrow (so that the player who launched the arrow teleports) and the parameter Motion: [] from the interaction entity, as I described earlier. After that, the arrow itself and the interaction are removed.

Actually all this works fine but in my opinion this approach is not ideal because of these problems:

  • Receiving damage on landing
  • The chance of the appearance of endermite

I would like to try to implement this functionality using the /teleport command to teleport a player to a landed arrow without an intermediary in the form of ender pearl. Basically I need to somehow take the Owner: [] parameter from the arrow and teleport a player (or even a mob) that has an identical UUID: []. But I have no idea how to do it. Perhaps using scoreboards it is possible to implement this, but I still don't understand them well enough, that's why I'm asking for help. Thanks!

New contributor
M1sha1L is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1
  • 1
    I would generally prefer using markers over interactions for extra data storage since they are the least lag intensive entity in the game. This doesn't do any damage here since I imagine there would be very few extra entities, but in bigger projects this can be noticable Commented Apr 26 at 5:07

1 Answer 1

2

Sounds like you want to run a teleport command once the arrow lands with the Owner as the entity being teleported. This sounds like a good use of the nbt selector argument. However, passing NBT into a command argument can only be done using macros. I don't know if you can create functions since you haven't tagged this question with , but if you can, the solution is very elegant:

Create a function file. I will call it arqade/teleport_owner.mcfunction. In it, there is will a single macro-style command:

$teleport @n[nbt={UUID:$(Owner)}] ~ ~ ~

It takes the nbt value of the Owner key and supplies it to the nbt selector argument. Now we just need to pass the NBT of the arrow into the macro command, which we can do by changing your ender pearl spawning command into a function call command:

execute as @e[type=arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] at @s run function arqade:teleport_owner with entity @s

I tested it (without the extra filtering of the arrow type and it works great. Also this has the added benefit of not needing any additional entities, so no more interaction entities


There is an alternate solution that does not use functions and involves binding a score to both the player and the arrow to resolve who to teleport.

I am describing this solution since you mentioned you need a solution which does not involve functions.

The key problem here is that the player's unique ID, an array, cannot be passed as an argument to be compared against. The only dynamic thing that can be compared against are scores. So the idea is that instead of assigning a player a UUID (a 256-bit number split into an array), we can use a score to the job for us. I can think of two approaches on how to tackle this:

  1. manually assign a score to the player, and copy that score to the arrow when it is being fired. This has the advantage of keeping the new "UIDs" very small, and you are guaranteed they are unique, but it can fail if the arrow being fired somehow does not get assigned. One possibility is maybe if someone is landing at shot at you while you are firing the arrow. How will you know which arrow to mark? This is still a very fringe situation, but this sort of solution is fairly standard
  2. A very "computer science-y" solution - Hash the UUID into the score. This has an inherent risk where two players might have the same UID, but this is extremely unlikely since we are dealing with very few players compared to the number of available scores, 232 = 4,294,967,296. We could implement a hash resolving function, but I really don't think this is neccesary.

I will write down the hashing approach since it is frankly really easy and requires less logic.

We have a freedom to choose the hashing function. We need something that takes in 4 int and converts it to one. The important thing is that whatever we get needs to be uniformly distributed. Since entity UUIDs are random and uniformly distributed, any part of them is also random and uniformly distributed. So why not just take the first int? This is a trivial and common hashing function.

Now for the implementation. In an impulse command block, run

scoreboard objectives add uid dummy

In a repeating command chain, run:

# hash entity UUID into a UID
execute as @e[type=!arrow] unless score @s uid matches -2147483648.. store result score @s uid run data get entity @s UUID[0] int 1
# hash arrow Owner UUID into a UID
execute as @e[type=arrow] unless score @s uid matches -2147483648.. store result score @s uid run data get entity @s Owner[0] int 1
# the teleport
execute at @e[type=arrow,nbt={data:{arrow_type:"teleport"},inGround:1b}] as @e[type=!arrow,scores={uid=-2147483648..}] if score @s uid = @n uid run teleport @s ~ ~ ~

You should seriously consider limiting the first command by type. If you plan is to only let players teleport, change it to @a. Same applies for the second selector of the third command.

The first and second command take the first int of the UUID (or Owner UUID in the second command) and stores it in the uid score for any entity that doesn't have it already. The -2147483648 in there is the minimum possible score, so this argument translates to "unless entity has a score in the uid objective".

The third command (which is shared between both uid strategies by the way) finds two entities and attempts to match their scores. The two selectors match the arrows that should trigger the teleport (marked by position) and the pool of entities that might be teleported as a result (marked by executor). The execute if score then compares the scores of all possible pairings to find the correct one: the @s matches the entity to be teleported thanks to execute as and @n matches the arrow thanks to the execute at. Finally, it teleports the filtered entity @s to the position of the arrow which is the relative origin also thanks to the execute at.

4
  • Thank you for the proposed solution but if you have the opportunity please write a solution without using data-packs. I would like to try an option that involves using only command blocks even if it doesn't work properly. Commented Apr 26 at 14:14
  • 1
    @M1sha1L edited. Now both solutions are written down. Still, I highly recommend looking into functions and datapacks, they really open a massive range of possibilites Commented Apr 26 at 18:28
  • Omg it works great and it works the way I wanted it to, which is the same with mobs as with players. Changes: 1 and 2 command need result between store and score; at the end of 1 and 2 command need only 1 instead of int 1. This is a very interesting approach to solving this problem and it seems that every time I learn a lot of new things, thanks to your answers to my questions. Thank you very much! Commented Apr 26 at 19:31
  • 1
    Thank you, I always forget the "result" part Commented Apr 27 at 4:50

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.