Minecraft – How to number entities returned by a target selector

minecraft-commandsminecraft-java-edition

I would like to test for entities in a certain area and number them.

A target selector always returns a list of selected entities in the order of the sort parameter.

For example, the following target selector will return a list of players within 100 blocks of the running command block, in random order:

@a[distance=..100,sort=random]

I would like to be able to number the entities returned by the target selector in two ways: through scoreboard objectives, and through scoreboard tags. For example, if the target selector returns players Alice, Joe, Bob, I would like for Alice to get scoreboard value 1, Joe to get 2, and Bob to get 3. If it returns players Joe, Alice, Bob, Joe would get 1, Alice would get 2, and Bob would get 3.

Using scoreboard tags, a tag named Player1 would be added to the first player, Player2 for the 2nd, and so on.

What is the best way to construct a functioning command mechanism for this purpose? Note, I would like an answer for all 3 non-arbitrary sorting methods, meaning nearest, furthest, and random.

Use [distance=..100] as your target selector template argument so that everyone's answer is consistent in what part is their target selector.

Best Answer

pppery's answer already has the best method for doing this with tags, it requires one command per tag. That's because tags are not made for this, they're made for binary states like "does this player have this property".

The missing piece to do it better with scoreboards is /scoreboard players operation, which allows you to copy a score from one place to another.

Let's start with pppery's idea of giving everyone a score of -1 initially, it works better than a tag:

scoreboard players set @a[distance=..100] id -1

And you need a fake player (or anything) to hold the current number:

scoreboard players set #current id 0

Now you repeat increasing that and copying it to another player who doesn't have an ID yet:

scoreboard players add #current id 1
scoreboard players operation @p[scores={id=-1}] id = #current id

If you don't rely on it being done all in one tick, you can simply loop the last two commands. If you have access to the world save, you can put them into a function that then calls itself if there are players left to handle, for example like this:

execute if entity @p[scores={id=-1}] run function fabian:assign_id

If you don't have access to the server data, there are some tricks you can do with command blocks to make them loop by changing their directions around, it's a bit complicated. You could also just put more chain command blocks down, containing the same two commands many times. But in that case, you can just hard-code the ID and only use one command block per ID.