How do I change the color of a sheep to match a block of wool in a chest?
The problem this comes down to is: How do I loop through the elements of an NBT array? Luckily I already have an answer to that: Dynamically sized NBT array
The "tedious method" would in your case require 864 (54×16) commands, like this:
/execute if entity @e[type=sheep,limit=1,nbt={Color:0b},scores={slot=0}] run data modify block ~ ~ ~ Items[{Slot:0b}].id set value "white_wool"
/execute if entity @e[type=sheep,limit=1,nbt={Color:0b},scores={slot=0}] run data modify block ~ ~ ~ Items[{Slot:0b}].id set value "orange_wool"
…
/execute if entity @e[type=sheep,limit=1,nbt={Color:0b},scores={slot=1}] run data modify block ~ ~ ~ Items[{Slot:1b}].id set value "white_wool"
…
That's very tedious. It's probably slightly better for performance than what I'm about to suggest, but it's not well generalisable for other cases and it's not as clever. ;)
I'll assume here that all slots are filled, so index and slot number are identical. If that is not the case, you'll have to use something like the "search" method from my linked post. I'll also assume that all the sheep have their desired slot number saved in a scoreboard called "slot
". You'll have to target them properly somehow, a scoreboard is a good idea for that.
First, copy the entire chest's Items
array somewhere else:
/data modify storage fabian:sheep items set from block ~ ~-1 ~ Items
And initialise a scoreboard to 0:
/scoreboard objectives add slot dummy
/scoreboard players set $current slot 0
Now you need a loop, I would suggest a function with recursive calls for this. I'll call mine fabian:copy_sheep
. Here is the complete function:
data modify storage fabian:sheep curr_item set from storage fabian:sheep items[0].id
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:white_wool"} run data merge entity @s {Color:0}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:orange_wool"} run data merge entity @s {Color:1}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:magenta_wool"} run data merge entity @s {Color:2}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:light_blue_wool"} run data merge entity @s {Color:3}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:yellow_wool"} run data merge entity @s {Color:4}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:lime_wool"} run data merge entity @s {Color:5}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:pink_wool"} run data merge entity @s {Color:6}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:gray_wool"} run data merge entity @s {Color:7}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:light_gray_wool"} run data merge entity @s {Color:8}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:cyan_wool"} run data merge entity @s {Color:9}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:purple_wool"} run data merge entity @s {Color:10}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:blue_wool"} run data merge entity @s {Color:11}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:brown_wool"} run data merge entity @s {Color:12}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:green_wool"} run data merge entity @s {Color:13}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:red_wool"} run data merge entity @s {Color:14}
execute as @e[type=sheep] if score @s slot = $current slot if data storage fabian:sheep {curr_item:"minecraft:black_wool"} run data merge entity @s {Color:15}
scoreboard players add $current slot 1
data remove storage fabian:sheep items[0]
execute if data storage fabian:sheep items[0] run function fabian:copy_sheep
Explanation:
Due to an oversight in the NBT path syntax items[0]{id:"minecraft:white_wool"}
does not work. Therefore you need to first copy that tag somewhere else, in this case fabian:sheep curr_item
.
Then you check every sheep for having the same value in the scoreboard "slot
" as the fake player "$current
". You can't use @e[scores={…}]
here, because you need a dynamic number. When the sheep matches, it checks if the current item's ID is "white_wool"
and if yes, sets its Color
tag to 0
(which is white). Then this repeats for "orange_wool"
and Color:1
and so on. This effectively means: Colour the sheep according to the current wool item.
The rest of the function increases the current slot counter, removes the first entry from the copied item list and continues the loop if there is an entry left. The reason why this is needed is that you can't dynamically access an array index based on a scoreboard value, so you need move the element forwards as many times as you want and then read from the fixed index 0.
Note that you need to do the setup again before repeating this process (except for the scoreboard creation).
I tried it here with a single chest, but it works the same with any inventory: