1

Is there a way to use commands to take the Motion data from one entity and merge it onto another? I want to let another entities move in unison with the player. Just copying the Motion tag does not work, because the X and Z motion seems to always be 0.

7
  • That duplicate is a bit of overkill, the important part for you is just: /data modify entity <selector> Motion set from entity <selector> Motion. Apr 28, 2020 at 7:25
  • I tried that and it works until you try to /data get from a player. for some reason a player's x and z motion are always 0.
    – Mi Taylor
    Apr 29, 2020 at 9:22
  • 1
    I did figure out how to do this with a player after extensive trial and error. Here are the commands... Let's say we are trying to move any entity with the tag "follow" with us when we move. We will need 2 repeating, unconditional, always active command blocks. execute as @e[tag=follow] at @s store result entity @s Pos[0] double 1 run data get entity @p Pos[0] execute as @e[tag=follow] at @s store result entity @s Pos[2] double 1 run data get entity @p Pos[2] Just by having those commands active, any entity with the "follow" tag will follow you. You may also add one for Pos[1] for jumps.
    – Mi Taylor
    Apr 29, 2020 at 9:26
  • It is also worth noting if you leave the scale for both x and z positions at 1 the entity will always be in the same block as you. Adjusting this scale will make the entity follow from a distance but always in the same dimension. I haven't tested this yet but adjusting the scale may also lead to longer follow distance at different places in the world but I may be wrong about that bit of math. If you want to add additional conditions to the commands and limit them to an area like I did, it works perfect.
    – Mi Taylor
    Apr 29, 2020 at 9:33
  • You can also start in a different place and let the thing mimic you somewhere else. The scale factor makes the area it moves through bigger or smaller. I didn't see anything with X and Z motion being always 0, but you seem to have already solved that problem. Apr 29, 2020 at 9:51

1 Answer 1

1

The Motion tag of players is weird. Player movement is controlled partially by the client, partially by the server, there are various checks, anti-cheats, latency handling mechanics, workarounds, etc. From my testing, Motion[0] and Motion[2] only seem to work when you sprint-jump, not when just sprinting, just jumping or any other type of manual movement, otherwise it's always 0.

The workaround is to use Pos instead. But that is much more complicated than copying the Motion tag from one entity to another, because if you copied it directly, the entity would just get teleported to where you are instead of relative to you. Of course you could use relative teleports, but for those you would need to hard-code the X, Y and Z distance to you. If that is variable (so a "relative relative teleport", I guess), then you need to do a bit of Maths.

In this example, all armour stands tagged "to_move" will get moved in unison with one player tagged "reference". If you want to have multiple reference players, you'll have to adjust the system, for example with IDs, by selecting the nearest player to each armour stand or something else. I did not do this here.

Initial setup:

/scoreboard objectives add x dummy
/scoreboard objectives add y dummy
/scoreboard objectives add z dummy
/scoreboard objectives add x_distance dummy
/scoreboard objectives add y_distance dummy
/scoreboard objectives add z_distance dummy

Whenever you want to store the relative distance between player and armour stand:

execute as @e[type=armor_stand,tag=to_move] store result score @s x_distance run data get entity @s Pos[0] 50
execute as @e[type=armor_stand,tag=to_move] store result score @s y_distance run data get entity @s Pos[1] 50
execute as @e[type=armor_stand,tag=to_move] store result score @s z_distance run data get entity @s Pos[2] 50
execute as @p[tag=reference] store result score @s x run data get entity @s Pos[0] 50
execute as @p[tag=reference] store result score @s y run data get entity @s Pos[1] 50
execute as @p[tag=reference] store result score @s z run data get entity @s Pos[2] 50
scoreboard players operation @e[type=armor_stand,tag=to_move] x_distance -= @p x
scoreboard players operation @e[type=armor_stand,tag=to_move] y_distance -= @p y
scoreboard players operation @e[type=armor_stand,tag=to_move] z_distance -= @p z

Whenever you want to update the armour stand's position (so usually every tick):

execute store result score @e[type=armor_stand,tag=to_move] x run data get entity @p[tag=reference] Pos[0] 50
execute store result score @e[type=armor_stand,tag=to_move] y run data get entity @p[tag=reference] Pos[1] 50
execute store result score @e[type=armor_stand,tag=to_move] z run data get entity @p[tag=reference] Pos[2] 50
execute as @e[type=armor_stand,tag=to_move] run scoreboard players operation @s x += @s x_distance
execute as @e[type=armor_stand,tag=to_move] run scoreboard players operation @s y += @s y_distance
execute as @e[type=armor_stand,tag=to_move] run scoreboard players operation @s z += @s z_distance
execute as @e[type=armor_stand,tag=to_move] store result entity @s Pos[0] double .02 run scoreboard players get @s x
execute as @e[type=armor_stand,tag=to_move] store result entity @s Pos[1] double .02 run scoreboard players get @s y
execute as @e[type=armor_stand,tag=to_move] store result entity @s Pos[2] double .02 run scoreboard players get @s z

Explanation:

The setup just creates scoreboards, that's easy.

The first three commands in the second code block let each armour stand store its current coordinates in its own x, y and z scoreboards… but not quite. You actually need less commands in total if you write it into x_distance, y_distance and z_distance instead and modify those values later. Otherwise x, y and z would get only used for copying to x_distance, y_distance and z_distance and later get overwritten anyway.
I use a scale factor here, because scoreboards are integers, so storing the position in them directly would round them down to the next lowest whole number, which would make the movement very choppy. The higher the scale factor is, the smoother the motion becomes, but at a scale factor above ≈71.58, you can get overflow issues when you are near the world border. The larger the scale factor, the smaller the part of the world is in which the system actually works correctly. With a factor of 50, it works everywhere and you can later conveniently multiply with 0.02. It's also precise enough that it's no longer noticeable that there's any limit to the precision at all.
The next three commands store the player's coordinates in their x, y and z scoreboards, this time for real and with the same scale factor. You actually need to use the same scale factor for armour stands and players, otherwise this system does not work correctly. I'm using /execute as here to avoid having to use @p[tag=reference] twice, that's a tiny performance improvement.
The last three commands in that code block subtract the player's X coordinate from the armour stand's X coordinate and the same for Y and Z, then store that in the armour stand's x_distance, y_distance and z_distance scores. For example, if you stand at X=10 and the armour stand is at X=15, the armour stand's x_distance score will be 15-10=5.

The first three commands in the last code block store the player's current position in each armour stand's x, y and z scores, as a starting point for the calculation.
The next three commands increase each armour stand's x, y and z scores by their x_distance, y_distance and z_distance scores, resulting in the position that they should get teleported to.
Finally, the calculated position gets copied to the armour stand's Pos tag, which instantly updates its actual position.

This system is actually really flexible:

  • If you want the armour stand to only update its position at certain times instead of every tick, you can just run the commands in the third code block less often and it will still work fine (unlike a direct copy of Motion would, even without the weird side effects that that has).
  • If you want to pause moving, you can just not run the commands. Afterwards, you can either decide to keep applying the same offset again by simply continuing to run the commands or you can use the new distance between player and armour stand, by simply running the commands in the second code block again.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .