Skills/nms/nms-data-component/SKILL.md
操作 Minecraft 1.21 DataComponentType 物品組件系統,讀寫 CustomData、MaxStackSize、Enchantments 等組件(Paper NMS + Mojang-mapped)/ Read and write 1.21 DataComponentType item components including CustomData, MaxStackSize, Enchantments
npx skillsauth add MrPippi/MPS nms-data-componentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
nms-data-component
操作 Minecraft 1.21 引入的 DataComponentType 物品組件系統,直接讀寫 CustomData、MaxStackSize、Enchantments、AttributeModifiers 等組件,取代舊版 NBT getTag()/setTag() 模式。
| 參數 | 範例 | 說明 |
|------|------|------|
| package_name | com.example.item | 產出類別所在 package |
| class_name | ItemComponentUtil | 工具類名稱 |
ItemComponentUtil.java — DataComponent 讀寫工具CustomDataHelper.java — CustomData(自定義 NBT 組件)操作參見 Skills/paper-nms/PLATFORM.md。關鍵依賴:
dependencies {
paperweight.paperDevBundle('1.21.1-R0.1-SNAPSHOT')
}
ItemComponentUtil.javapackage com.example.item;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.component.ItemLore;
import net.minecraft.world.item.component.Unbreakable;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack;
import java.util.Optional;
@SuppressWarnings("UnstableApiUsage")
public final class ItemComponentUtil {
private ItemComponentUtil() {}
/** 讀取指定 DataComponentType 的值。 */
public static <T> Optional<T> get(
org.bukkit.inventory.ItemStack item, DataComponentType<T> type) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
return Optional.ofNullable(nms.get(type));
}
/** 設定指定 DataComponentType 並回傳修改後的 Bukkit ItemStack(不可變)。 */
public static <T> org.bukkit.inventory.ItemStack set(
org.bukkit.inventory.ItemStack item, DataComponentType<T> type, T value) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
nms.set(type, value);
return CraftItemStack.asBukkitCopy(nms);
}
/** 移除指定 DataComponentType。 */
public static org.bukkit.inventory.ItemStack remove(
org.bukkit.inventory.ItemStack item, DataComponentType<?> type) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
nms.remove(type);
return CraftItemStack.asBukkitCopy(nms);
}
/** 檢查是否含有指定組件。 */
public static boolean has(
org.bukkit.inventory.ItemStack item, DataComponentType<?> type) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
return nms.has(type);
}
// ─── 常用組件快捷 ─────────────────────────────────────────────────
/** 設定物品最大堆疊數。 */
public static org.bukkit.inventory.ItemStack setMaxStackSize(
org.bukkit.inventory.ItemStack item, int size) {
return set(item, DataComponents.MAX_STACK_SIZE, size);
}
/** 設定物品為不可破壞(顯示 Unbreakable 標籤)。 */
public static org.bukkit.inventory.ItemStack setUnbreakable(
org.bukkit.inventory.ItemStack item, boolean showTooltip) {
return set(item, DataComponents.UNBREAKABLE, new Unbreakable(showTooltip));
}
/** 讀取附魔列表。 */
public static Optional<ItemEnchantments> getEnchantments(
org.bukkit.inventory.ItemStack item) {
return get(item, DataComponents.ENCHANTMENTS);
}
/** 讀取自定義模型資料(CustomModelData int)。 */
public static Optional<Integer> getCustomModelData(
org.bukkit.inventory.ItemStack item) {
return get(item, DataComponents.CUSTOM_MODEL_DATA)
.map(cmd -> cmd.value()); // CustomModelData.value()
}
}
CustomDataHelper.java(自定義 NBT 組件)package com.example.item;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomData;
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack;
import java.util.Optional;
/**
* CustomData 組件操作(對應舊版 getTag().getCompound("custom_key") 模式)。
*
* 1.21 的 CustomData 是獨立組件,儲存在 DataComponents.CUSTOM_DATA 下,
* 不再直接在 root tag 層級存放自定義鍵。
*/
@SuppressWarnings("UnstableApiUsage")
public final class CustomDataHelper {
private CustomDataHelper() {}
/** 讀取 CustomData 組件中的指定字串欄位。 */
public static Optional<String> getString(
org.bukkit.inventory.ItemStack item, String key) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
CustomData customData = nms.get(DataComponents.CUSTOM_DATA);
if (customData == null) return Optional.empty();
CompoundTag tag = customData.copyTag();
if (!tag.contains(key)) return Optional.empty();
return Optional.of(tag.getString(key));
}
/** 寫入字串到 CustomData 組件,回傳修改後的 Bukkit ItemStack。 */
public static org.bukkit.inventory.ItemStack setString(
org.bukkit.inventory.ItemStack item, String key, String value) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
CustomData existing = nms.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
CompoundTag tag = existing.copyTag();
tag.putString(key, value);
nms.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
return CraftItemStack.asBukkitCopy(nms);
}
/** 寫入整數到 CustomData 組件。 */
public static org.bukkit.inventory.ItemStack setInt(
org.bukkit.inventory.ItemStack item, String key, int value) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
CustomData existing = nms.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY);
CompoundTag tag = existing.copyTag();
tag.putInt(key, value);
nms.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
return CraftItemStack.asBukkitCopy(nms);
}
/** 移除 CustomData 中的指定欄位。 */
public static org.bukkit.inventory.ItemStack removeKey(
org.bukkit.inventory.ItemStack item, String key) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
CustomData existing = nms.get(DataComponents.CUSTOM_DATA);
if (existing == null) return item;
CompoundTag tag = existing.copyTag();
tag.remove(key);
nms.set(DataComponents.CUSTOM_DATA, CustomData.of(tag));
return CraftItemStack.asBukkitCopy(nms);
}
/** 取得完整的 CustomData CompoundTag 副本。 */
public static CompoundTag getTag(org.bukkit.inventory.ItemStack item) {
ItemStack nms = CraftItemStack.asNMSCopy(item);
CustomData customData = nms.get(DataComponents.CUSTOM_DATA);
return customData != null ? customData.copyTag() : new CompoundTag();
}
}
src/main/java/com/example/
├── MyNmsPlugin.java
└── item/
├── ItemComponentUtil.java
└── CustomDataHelper.java
ItemComponentUtil / CustomDataHelper 操作 NMS Copy,不直接修改世界狀態,可在任意執行緒呼叫player.getInventory().setItem()),必須在主執行緒Skills/_shared/nms-threading.md| 錯誤 | 原因 | 解法 |
|------|------|------|
| get() 回傳 empty | 組件未設定 | 使用 getOrDefault() 提供預設值 |
| CustomData 資料丟失 | 使用舊版 getTag() 寫入(1.21 不相容) | 改用 CustomDataHelper.setString() |
| CustomModelData.value() 不存在 | 不同 1.21 子版本 API 差異 | 檢查 Paper Javadoc 確認方法名 |
| 組件設定後不生效 | 操作的是 NMS Copy 而非原物件 | 確保用 CraftItemStack.asBukkitCopy() 回傳並更新 inventory |
development
透過 NMS Scoreboard/Objective/Team API 操作 sidebar、tablist 顯示名稱與計分板(Paper NMS + Mojang-mapped)/ Operate sidebar, tablist, and scoreboard via NMS Scoreboard/Objective/Team API
research
操作 GameProfile 進行 skin 注入,用於 NPC 外觀設定與假玩家實體(Paper NMS + Mojang-mapped)/ Manipulate GameProfile for skin injection used in NPC appearance and fake player entities
tools
透過 ClientboundLevelParticlesPacket 實現進階 NMS 粒子效果:客戶端專屬、大量粒子、自定義參數(Paper NMS + Mojang-mapped)/ Advanced NMS particle effects via ClientboundLevelParticlesPacket with per-client and bulk support
documentation
直接操作 CompoundTag 讀寫物品、實體、方塊實體的 NBT 資料(Paper NMS + Mojang-mapped)/ Read and write NBT data on items, entities, and block entities via CompoundTag