My brain refuses to explain a problem without context, so please bear with me.
I'm attempting to make a PVP map, but I want there to be a specific and custom "death message" for arrows being "hit" because there are multiple different arrows I intend on having (custom tipped arrows); e.g. I have an arrow that should be an instant kill that I want to have announce *target* was sniped by *source*
. Because I have showDeathMessages
disabled for this and other ways of dying, and I also want there to be a specific set of commands to run post-death, I can't simply kill the target with the arrow and let Minecraft's main death messages handle it.
Here's the actual problem. In order to do this while still keeping it accurate to the target's health, I want to calculate the speed of an arrow and, provided it causes the damage of the arrow to be equal to or higher than said health, run a command; in this case, I want to teleport the target back to spawn.
As of this moment in time. I already have the following set up;
- A scoreboard (uuid) set up to find and match UUIDs from an Arrow's
Owner[0]
to a player'sUUID[0]
— this was made assuming that the first object in the IntArray will always be unique (due in part to UUID's meaning); - A tag for it having been found, named "ping";
- A command chain running every tick to find, compare, and match said UUIDs;
- Scoreboards (vx, vy, and vz) set up to find and store an Arrow's three
Motion
tags; - Command chains running every tick to do the above, provided the Arrow isn't in the ground
The primary issue is that the command (below) I'm attempting to use to determine a "hit" isn't doing anything. For this, I'm assuming a fully charged bow and that an arrow needs to be less than half a block near the target before Minecraft actually recognizes it as a hit;
execute as @e[tag=ping,scores={vx=2..}] at @s if entity @p[distance=..0.5,scores={health=..6}] unless score @p uuid = @s uuid run tp @p 127 179 8
What I understand the command to be doing should be;
- As every entity with the tag
ping
whosevx
score is 2 or larger,- …if the nearest player is within .5 blocks and has <=6 health,
- …unless that player has the same UUID as the Owner tag of the entity,
- teleport the player to the coordinates.
Instead, the arrow simply hits and damages the player regardless of health, and thus so will kill the player before they teleport anywhere. Since I want other commands and death messages to run and be displayed after teleporting, I can't let it just kill them.
Is the syntax of the command wrong? I thought it was a problem with the distance
selector (at if entity @p [distance=..0.5]...
), but even after setting that to ..1
instead of ..0.5
, it still did nothing.
Best Answer
Issues with your command
In your question, you are attempting to detect when a player is about to be hit by an arrow. I assume you are doing this because you want to maintain the Owner of the arrow, a.k.a who shot it. This will then be used in your death message.
To do this, you calculate its speed and then detect when it is within half a block distance. But as you said, it did not work. Here are some possible reasons your command failed:
Issue 1: random damage
~From the Official Minecraft Wiki.
Issue 2: projectile motion
Issue 3:
distance
selectorYou use the
distance=..0.5
selector, but this is not what you need. Intuituvely, it seems like this would detect if the arrow is within0.5
blocks of the player's hitbox, but the distance selector selects other entities whose feet/origin are within a0.5
spherical radius. This means that if the arrow hits the head of a player, approximately 2 blocks above the player's feet/origin, this will fail the distance check.This can be fixed by using a volumetric cuboid selection,
dx
,dy
, anddz
, like so:@p[dx=0]
. This selects the nearest player whose hitbox is within the same block as the arrow. This isn't perfect, either, though.Issue 4: storing Motion
Issue 5: using only one part of the UUID
The Situation
I'm glad you gave context, because your situation is quite complex. You need to detect arrow hits, what type of arrow it was, if the player died, the player who killed them, etc.
I didn't really see how what you tried would manage to fit in with all these factors, so I came up with a different approach.
To solve your problem, we need a few key components.
To identify the custom arrow, we will be using an amplifier-based identification system. This will allow you to create all the special arrow effects and death messages you want.
To detect where the arrow lands, we will be using a passenger system. This is primarily used to save the tipped arrow's custom effect even after the arrow hits a player and ceases to exist. It will also be useful if we want to run a special arrow effect at the location the arrow hit.
To detect a player death and their killer, we will be using good ol' scoreboards.
These will all be explained in the next section.
The Datapack Explanation
My answer here uses a datapack, because for large projects like these, command blocks lack the necessary power. Here is the file. Make sure to unzip it, then place it in
.minecraft/saves/YOUR_WORLD_NAME/datapacks
.I recommend to download the datapack so you can follow along with the explanation.
The explanation will begin with the
main.mcfunction
file, located indata/custom_arrows/functions/dont_edit
. This function will run every tick, as specified indata/minecraft/tags/functions/tick.json
.First line of the file—similar to your approach, I use a tag called
checked
to initialize all the arrows that are shot. These new arrows run the functiondata/custom_arrows/functions/dont_edit/new
:This might seem like a lot, but all it does is summon a new arrow that is identical, then killing the original. It does this by using lots of
data modify
commands to copy all the important data. The only difference is that it has a passenger riding on it; amarker
entity. As explained in the passenger system video, This marker entity will remain behind even when the projectile hits an entity and disappears. This is important, because we want to know what arrow hit the player, even if they died. To do this, we also copy the original arrow'sCustomPotionEffects
onto themarker
entity'sdata
tag.Jumping back out to the
main.mcfunction
file, we arrive at the second line:Here, several new players come onto the scene. The
custom_arrows:is_riding_arrow
predicate, adeaths
score, and akilled_by_player
score. Before this gets explained, it is probably best to jump into another mcfunction file first,init.mcfunction
. (data/custom_arrows/functions/dont_edit/init.mcfunction
.)This file will run every time the server is reloaded (
/reload
) or every time the world is loaded, as specified bydata/minecraft/tags/functions/load.json
. It is a great place to put initialization commands. In this case,init.mcfunction
only contains 3 commands:2 of these commands we saw in
main.mcfunction
,deaths
andkilled_by_player
. There is a third,player_kills
. Together, these 3 scoreboards allow us to identify a killer and a victim, although not 100% accurately. If 2 players are killed within the same tick, there will be 2 players with a score ofdeaths=1..
andplayer_kills=1..
. This could result in the incorrect player being identified as the killer/victim. If there is a better way to do this, I am not aware of it.Before we jump back to
main.mcfunction
, we also need to know what a predicate is. Predicates are a powerful tool we can use to check many many different properties. They are stored in JSON format, so I use this generator to create them.In this datapack, a custom predicate,
is_riding_arrow
, was made (data/custom_arrows/predicates/is_riding_arrow.json
):As the name suggests, it checks if the entity running the command is riding an arrow. It also checks if the entity has the tag,
arrow_rider
(which was given to our marker entity). Pretty simple.BACK TO OUR
main.mcfunction
file, we can begin to make sense of the second line, re-pasted here:As the comment describes, this command will execute as all marker entities who are NOT riding an arrow. This is because when the arrow hits an entity, it will disappear, and the marker entity will no longer be riding an arrow. This serves as our hit detection. The marker entity then checks to see if a player was killed by another player. If so, the marker entity runs the
arrow_kill
function:(As you may have noticed, some of the files are located in a folder named
dont_edit
, and this one even has the comments, "### Edit this stuff" and "### Do not delete" at the top and bottom, respectively. Yes, to add your own custom arrows, you will have to edit these files.)In
arrow_kill.mcfunction
, the marker entity is checked to see what data it holds. Remember innew.mcfunction
, when we copied the arrow'sCustomPotionEffects
onto it? Here, it sees its purpose! Even after the arrow has disappeared after killing an entity, we can still identify which custom arrow it was. We do this by checking theCustomPotionEffects
's amplifier, which is our custom arrow identification system. This does mean that your custom arrows cannot be the vanilla default tipped arrows! The vanilla arrows do not contain anyCustomPotionEffects
, onlyPotion
.Once we have identified what arrow killed the player, we can run another function,
killed_by_sniper_arrow.mcfunction
:This is the fun part. In this example custom arrow file, several events occur when a player is killed with an arrow of Luck I. This example is also the most relevant to your question, since it sees the usage of a custom death message and teleporting the player to spawn, as you wanted. Alternatively, under this system, you could just set their spawnpoint there.
I also included another example, the silverfish arrow, which runs when a player is killed with an arrow of Luck II:
Fun stuff.
If you've been following along with the datapack file, you might have noticed 2 similarly named files:
hit_by_sniper_arrow.mcfunction
andhit_by_silverfish_arrow.mcfunction
. The files we just looked at are the death event functions, but we will also need functions for the hit event. The hit event function requires several conditions to run, starting back at our good oldmain.mcfunction
's third line:If the player survived the arrow hit, the arrow will still disappear, and the marker entity will still dismount. To differentiate between a hit and a death, we can use the fact that players will lose their effects on death.
So, we detect this by simply executing as all players who have the Luck effect, and having them run the function,
arrow_hit
:Similarly to
arrow_kill
, this function is a directory for identifying the specific amplifier they have been affected with. This will make them run the corresponding custom arrow file. Let's look into thehit_by_sniper_arrow
function:Like before, everything that goes on here is up to you.
We are almost through the entire datapack! These are the final lines of
main.mcfunction
:Quite self-explanatory. If the marker entity is no longer riding an arrow, (but didn't run the
hit
orkill
functions, which kills the marker after), we just kill the marker entity so it doesn't cause any troubles.FINALLY, we reset the scores used for killer/victim detection.
Final Words
That was a lot of time spent writing the datapack, debugging, and writing this answer! Unfortunately, I was unable to test it in a multiplayer environment on friends, because... well yea I just wasn't able to. If you come across any bugs, I'll be putting this up on a Planet Minecraft page, where I can share this datapack with others and you can leave a comment.