『KubeJS新手教程?』用工作台来附魔吧,把铁砧放一边 | 我的世界 Minecraft 魔改
在写工作台配方时,你是否想过要实现些特殊的效果呢

Transform Ingredients
在有序/无序配方中,我们可以用一些函数来实现“材料”的转换,以达到我们的需求:
.damageIngredient(IngredientFilter filter, int damage?) // 在你合成时,损耗/增加物品的耐久度
.replaceIngredient(IngredientFilter filter, ItemStackJS item) // 将物品替换为其他的物品 (例如水桶合成后变为桶)
.keepIngredient(IngredientFilter filter) // 将物品保留在合成格中
.customIngredientAction(IngredientFilter filter, String customId) // 运行你的自定义脚本,记得先注册哦
IngredientFilter 材料过滤器可以是
- 物品 ItemStackJS ('minecraft:dirt', Item.of('minecraft:diamond_sword').ignoreNBT(), 等)
- 物品在合成格的位置/索引 (0, 1, 等)
- 物品和/或索引 ( {item: 'something', index: 0}, 等)
不同的函数对应不同的使用场景
而我们这次需要用到的,就是 `customIngredientAction` 自定义的材料变化函数

Register Custom Ingredient Action
使用 `Ingredinet` 下的方法 `registerCustomIngredientAction` 来注册我们的自定义函数
Ingredient.registerCustomIngredientAction('apply_enchantment', (itemstack, index, inventory) => {})
其中 `itemstack` 代表指定的物品,`index` 代表合成格的索引,`inventory` 代表合成格包含的所有物品
我们可以通过 `NBT` 来修改物品的附魔,这里有两种方案
一种方案:简单的添加 `NBT` 会覆盖掉物品原有的附魔,因此只适合没有附魔的物品使用
Ingredient.registerCustomIngredientAction('apply_enchantment', (itemstack, index, inventory) => {
// 通过 inventory 来获取 附魔书的NBT
let enchantments = inventory.get(inventory.find(Item.of('minecraft:enchanted_book').ignoreNBT())).nbt
// 将 附魔书的NBT 中关于附魔的部分添加到 物品
itemstack.nbt.merge({Enchantments: enchantments.get('StoredEnchantments')})
// 返回 添加了附魔的物品
return itemstack
})
另一种方案:完全实现了铁砧的功能,除了消耗经验和发出音效
Ingredient.registerCustomIngredientAction('apply_enchantment', (itemstack, index, inventory) => {
// 复制物品 和 获取附魔书
let itemstack1 = itemstack.copy()
let itemstack2 = inventory.get(inventory.find(Item.of('minecraft:enchanted_book').ignoreNBT()))
// 分别获取 物品 和 附魔书 的所有附魔
let map = EnchantmentHelper.getEnchantments(itemstack1)
let map1 = EnchantmentHelper.getEnchantments(itemstack2)
//对 附魔书的附魔 进行遍历
let var22 = map1.keySet().iterator()
label172: while(true) {
let enchantment1
do {
// 当没有下一个附魔时跳出循环
if(!var22.hasNext()) break label172
// 获取下一个附魔
enchantment1 = var22.next()
} while(enchantment1 == null)
// 获取该附魔在 物品 和 附魔书 上的等级
let i2 = map.getOrDefault(enchantment1, 0)
let j2 = map1.get(enchantment1)
// 当附魔等级一致时增加一级,否则取最大值
j2 = i2 == j2 ? j2 + 1 : Math.max(j2, i2)
// 标记:该附魔能否附加在 物品 上
let flag1 = enchantment1.canEnchant(itemstack)
// 对 物品的附魔 进行遍历
let var17 = map.keySet().iterator()
while(var17.hasNext()) {
let enchantment = var17.next()
// 物品不拥有该附魔 且 该附魔无法附加到物品上时,标记为否
if(enchantment != enchantment1 && !enchantment1.isCompatibleWith(enchantment)) {
flag1 = false
}
}
if(flag1) {
// 确保 附魔等级 不超过上限
if(j2 > enchantment1.getMaxLevel()) {
j2 = enchantment1.getMaxLevel()
}
// 将 物品的附魔 与 附魔书的附魔 合并,但并不是附加到物品上
map.put(enchantment1, j2)
}
}
let listtag = [] // 缓存附魔标签
// 对 合并后的Map 进行遍历
let var3 = map.entrySet().iterator()
while(var3.hasNext()) {
let entry = var3.next()
// 获取 经过筛选的附魔
let enchantment = entry.getKey()
if(enchantment != null) {
let i = entry.getValue()
// 当 附魔 不为空时,添加到 listtag 中
listtag.push(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), i))
}
}
if(!listtag) {
// 当 listtag 为空时,移除物品的附魔标签
itemstack1.getItemStack().removeTagKey('Enchantments')
} else {
// 当 listtag 不为空时,为物品添加附魔标签
itemstack1.getItemStack().addTagElement('Enchantments', listtag)
}
// 返回 附魔后的物品
return itemstack1
})
这里用到了原版的附魔帮手 `EnchantmentHelper`,所有要先导入
let EnchantmentHelper = java('net.minecraft.world.item.enchantment.EnchantmentHelper')
因此,该脚本在 1.16.5 与 1.18.2+ 的写法并不相同

配方
最后只需要在写配方时调用我们的自定义函数就可以了
onEvent('recipes', event => {
event.shapeless('minecraft:book', ['#kaka:tools', Item.of('minecraft:enchanted_book').ignoreNBT()])
.customIngredientAction('#kaka:tools', 'apply_enchantment')
})
// 我用了自定义的 物品标签 'kaka:tools', 所以需要另外注册
onEvent('tags.items', event => {
event.add('kaka:tools', 'minecraft:netherite_pickaxe')
event.add('kaka:tools', ['minecraft:diamond_pickaxe'])
})
就是这样,非常有趣的配方函数,希望你能写出自己想要的效果
谢谢你的阅读,请不要忘了动动手指给我一个免费点赞哦

最后是总览:并没有注释哦,你还记得它们的作用吗
let EnchantmentHelper = java('net.minecraft.world.item.enchantment.EnchantmentHelper')
onEvent('recipes', event => {
Ingredient.registerCustomIngredientAction('apply_enchantment', (itemstack, index, inventory) => {
// let enchantments = inventory.get(inventory.find(Item.of('minecraft:enchanted_book').ignoreNBT())).nbt
// itemstack.nbt.merge({Enchantments: enchantments.get('StoredEnchantments')})
// return itemstack
let itemstack1 = itemstack.copy()
let itemstack2 = inventory.get(inventory.find(Item.of('minecraft:enchanted_book').ignoreNBT()))
let map = EnchantmentHelper.getEnchantments(itemstack1)
let map1 = EnchantmentHelper.getEnchantments(itemstack2)
let var22 = map1.keySet().iterator()
label172: while(true) {
let enchantment1
do {
if(!var22.hasNext()) break label172
enchantment1 = var22.next()
} while(enchantment1 == null)
let i2 = map.getOrDefault(enchantment1, 0)
let j2 = map1.get(enchantment1)
j2 = i2 == j2 ? j2 + 1 : Math.max(j2, i2)
let flag1 = enchantment1.canEnchant(itemstack)
let var17 = map.keySet().iterator()
while(var17.hasNext()) {
let enchantment = var17.next()
if(enchantment != enchantment1 && !enchantment1.isCompatibleWith(enchantment)) {
flag1 = false
}
}
if(flag1) {
if(j2 > enchantment1.getMaxLevel()) {
j2 = enchantment1.getMaxLevel()
}
map.put(enchantment1, j2)
}
}
let listtag = []
let var3 = map.entrySet().iterator()
while(var3.hasNext()) {
let entry = var3.next()
let enchantment = entry.getKey()
if(enchantment != null) {
let i = entry.getValue()
listtag.push(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), i))
}
}
if(!listtag) {
itemstack1.getItemStack().removeTagKey('Enchantments')
} else {
itemstack1.getItemStack().addTagElement('Enchantments', listtag)
}
return itemstack1
})
event.shapeless('minecraft:book', ['#kaka:tools', Item.of('minecraft:enchanted_book').ignoreNBT()])
.customIngredientAction('#kaka:tools', 'apply_enchantment')
})
onEvent('tags.items', event => {
event.add('kaka:tools', 'minecraft:netherite_pickaxe')
event.add('kaka:tools', ['minecraft:diamond_pickaxe'])
})
其实还有改输出的函数 `modifyResult` 哦,想想该怎么写吧
