7

So far, I've been able to detect when a diamond is placed into a chest's inventory but how can I detect who placed that diamond?

I'd prefer not to use the nearest player because someone else could potentially be falsely identified. (I have a command chain that trades players emeralds in exchange for experience levels and it also sometimes robs random nearby players.)

Some context: I'm making a race to be the first to deposit a diamond. I could constrain the player accessing the chest and just check who is standing on a block, but if I did that, I could also just test the player's inventory directly. But that seems boring. Adding the chest adds to the drama, I feel. Like, if someone fumbles last minute and deposits dirt on accident, someone else could easily win, which is fun.

My command chain is currently:

if block x y z chest{Items:[{id:"minecraft:diamond"}]}
say Diamond Detected

Edit: The diamonds are mined and as such, I will not necessarily be able to tag them for each player. Another user suggested I could scan the inventories of the users at every tick and tag the diamonds in their inventory with their name. I don't know how to do this, though I believe this is the direction where I will find my answer.

2
  • From what you said I suppose you're running a server. Spigot has an inventorymoveitem command but since I'm not sure exactly how to program a server, I can't answer. – A.Shetye Jun 19 '20 at 4:00
  • @A.Shetye I'm using bukkit I've heard alot about spigot but I'm just getting back into running a server after 5 years out of the game. I'm just using vanilla command blocks for this, so there's not really a difference, other than lag concerns but I can't do much about that other than enabling QA in my firewall. I do also have some python/bash scripts interacting with RCON. So I've kinda developed this pseudo API for bringing game state into external applications. – Robert Talada Jun 19 '20 at 5:59
3

If you don't know who has each diamond

Step one

Give each player a unique scoreboard ID. See this related question for how to do that.

Step two

Run the following command in a repeating, always active command block:

execute as @e[type=item,nbt={Item:{id:"minecraft:diamond"}}] run data merge entity @s {Item:{tag:{Unclaimed:1b}}

This gives each diamond item on the ground a custom Unclaimed tag, allowing you implement Step 3 without 30+ command blocks per player

Step three

Once for each player who could be playing the map, run in a repeating command block:

clear @a[scores={Id=1}] diamond{Unclaimed:1b} 1

and then, in a conditional chain command block that the repeating command block is pointing to

give @a[scores={Id=1}] diamond{PlayerOwns:1b} 1

Repeat this for each player, using scores={Id=2} and PlayerOwns:2b for the second player and so on.

Step four

Now that each diamond has a tag describing whose it is, you can use the technique described in ExpertCoder14's answer to determine who put a diamond in the chest.

This has a known bug that if Alice puts a diamond in a container, and then Bob takes the diamond out of the container (and never drops and picks it up again), the diamond is still interpreted as belonging to Alice -- but I actually like that if I understand what you're doing correctly; if you stole someone else's diamond from a chest instead of mining your own, that means you're trying to cheat… karma!

If you want a more seamless experience, you may want to interest yourself in player inventory modification. With the method above, the diamond is visibly replaced by a different one, you can use this to make a seamless replacement.

0
3

If you know who has each diamond

If you know who has each diamond, you can give each diamond a custom NBT tag. For example, if there are 5 players, you can use a custom NBT tag named something like PlayerOwns, and when given to the player, you can set it to the player's number. For example, player 1 will get diamond with the custom tag set to 1.

For example:

/give Player1 diamond{PlayerOwns:3b}

and the same with the other players.

You can then test for the item using:

/execute if block x y z chest{Items:[{id:"minecraft:diamond",tag:{PlayerOwns:3b}}]} run say Player 3 wins!

Notes

  • Be careful not to use a tag that is used for other purposes! Choose a tag name that won't be used by Minecraft. For example, don't name your custom tag CanPlaceOn, because that will mess up the system.
  • Remember to specify the data type at the end. In the examples above, I use a TAG_Byte because it uses the least storage and goes up to 255 players. You need to specify the data type at the end of your entry for both setting and testing, like 4b for Byte or 175s for Short (up to 32767).
  • A tip for best practice is to use the correct type of number tag for your needs. For example, Byte tags are preferred for smallest numbers, because they take up the smallest amount of space, but they only support numbers from -128 to 127.

Here are some links if you would like to check out more about these:

1
  • 1
    I appreciate your thorough answer, but I won't know who has each diamond. The diamonds are mined. I'm making almost like a Minecraft triathlon, one of the events is who can get from no inventory to diamond and place it in this chest in the least amount of time. Making the players have to think about making it back safely is necessary, simply finding a diamond is too easy. – Robert Talada Jun 20 '20 at 16:21

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.