1

I am trying to make a printer with sheep. I have a double chest for the printer input and sheep correspond to the slots in the chest. There are 54 sheep corresponding to the 54 slots. What command can I run to make the color of wool in a specific slot in a chest the same color as the corresponding sheep? And how can I copy it 54 times so I can do it for each slot/sheep?

  • 2
    Should be pretty straightforward with the brute-force method, but that requires 864 (54*16) commands. I have a few vague ideas how to get that number down, but they're complicated and I can't play Minecraft now (next in about 3 weeks). One of those ideas involves variable array access. Maybe you can do something with that already. The wool->sheep conversion might not be possible with less than 16 commands, because sheep still store their colour as a number, but wool stores it as a word (block state). – Fabian Röling Apr 5 at 18:37
1

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:

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.