MC-131346 was fixed, so the new answer to this question is: It just works. /give @s water_bucket{CanPlaceOn:["stone"]}
gives you the proper water bucket that can only be placed on stone.
Here is the old answer for reference, in case you're playing in an older version:
As OnePointZero said, usually CanPlaceOn
should just work for buckets, but due to MC-131346 it doesn't. But there's an easier way to work around it:
Give the player a retextured item that he doesn't usually have anywhere else in your map and that also doesn't appear as a block in it. One idea would be a structure void or, if the item remodeling is too difficult, a sapling, bed, rail or other placeable item with a different texture than the block, as long as it's not anywhere else in the map.
That item has to have the CanPlaceOn
tag, here demonstrated with a stone:
/give @s stone{CanPlaceOn:["sandstone"]}
Then you track the usage of this item, like this:
/scoreboard objectives add placedStone minecraft.used:minecraft.stone
And whenever someone places it, you replace the block in the world with water:
/execute at @a[scores={placedStone=1..}] run fill ~-7 ~-7 ~-7 ~7 ~7 ~7 water replace stone
Luckily /fill
already updates all blocks consistently, so it will begin to flow automatically and you don't have to bother with the inconsistent updates of /setblock
.
Now you just reset the scoreboard for later use:
/scoreboard players set @a[scores={placedStone=1..}] placedStone 0
The last two commands go into repeating command chain or a function. The second command block can be conditional.