【1.21.4】Spigot+NBT APIでItemStackにコンポーネント「can_break」を設定する

# 1.したいこと
```:↓これがしたい
/give @p iron_pickaxe[can_break={predicates:[{blocks:"stone"}]}] 1
```

なんとSpigot APIは`can_break`(旧can_destroy)に対応していません! ←なんで?

NMSはさっぱりなので外部ライブラリ「[NBT API](https://www.spigotmc.org/resources/nbt-api.7939/)」を使用した。

# 2.結論

:::note warn
執筆現在、1.21.5でcan breakのアイテムフォーマットに再度の変更が予定されています。
[※Minecraft wiki](https://ja.minecraft.wiki/w/%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88/can_break)
:::

<details><summary>サンプルコード(Java)</summary>


:::note warn
Java用のコードを用意するのが面倒だったのでChatGPTに変換してもらいました。
一通り目は通してますが動かなかったらごめんなさい
:::

```java:Java by ChatGPT
import java.util.List;
import java.util.ArrayList;
import de.tr7zw.nbtapi.NBT;
import de.tr7zw.nbtapi.ReadWriteNBT;
import de.tr7zw.nbtapi.ReadWriteNBTCompoundList;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;

public class ItemUtils {
    public static ItemStack setCanDestroy(ItemStack itemStack, List<Material> target, boolean showInToolTip) {
        NBT.modifyComponents(itemStack, nbt -> {
            ReadWriteNBTCompoundList predicates = nbt.getOrCreateCompound("can_break").getCompoundList("predicates");
            
            for (Material material : target) {
                predicates.addCompound().setString("blocks", String.valueOf(material.getKey()));
            }
            
            nbt.getOrCreateCompound("can_break").setBoolean("show_in_tooltip", showInToolTip);
        });
        return itemStack;
    }

    public static ItemStack setCanDestroy(ItemStack itemStack, List<Material> target) {
        return setCanDestroy(itemStack, target, false);
    }

    public static ItemStack setCanDestroy(ItemStack itemStack, Material target) {
        List<Material> list = new ArrayList<>();
        list.add(target);
        return setCanDestroy(itemStack, list, false);
    }
}
```
</details>
<details open><summary>サンプルコード(Kotlin)</summary>

```kotlin:Kotlin
import de.tr7zw.nbtapi.NBT
import de.tr7zw.nbtapi.iface.ReadWriteNBT
import de.tr7zw.nbtapi.iface.ReadWriteNBTCompoundList
import org.bukkit.Material
import org.bukkit.inventory.ItemStack

object ItemUtil {
    fun setCanDestroy(itemStack: ItemStack, target: MutableList<Material>, showInToolTip: Boolean): ItemStack {
        NBT.modifyComponents(itemStack) {nbt: ReadWriteNBT ->
            val predicates: ReadWriteNBTCompoundList =nbt.getOrCreateCompound("can_break").getCompoundList("predicates")

            target.forEach { material: Material ->
                predicates.addCompound().setString("blocks", material.keyOrNull.toString())
            }

            nbt.getOrCreateCompound("can_break").setBoolean("show_in_tooltip", showInToolTip)
        }
        return itemStack
    }

    fun setCanDestroy(itemStack: ItemStack, target: MutableList<Material>): ItemStack {
        return setCanDestroy(itemStack, target, false)
    }

    fun setCanDestroy(itemStack: ItemStack, target: Material): ItemStack {
        return setCanDestroy(itemStack, mutableListOf(target), false)
    }
}
```
</details>

# 3.参考
- NBT-API wiki. Example Usages. Jul 22, 2024. https://github.com/tr7zw/Item-NBT-API/wiki/Example-Usages#set-a-skulls-skin