前言
在KubeJS的Discord频道内有不少神奇的脚本,令人眼界大开,不过国内访问Discord比较困难,而且1.16.5的Example Scripts子频道藏得有点深。现得频道同意,搬运一些Scripts到百科来,分享给各位。
正文
简单矿辞统一
放在server_scripts文件夹内,该脚本由ChefArug提供。
只支持“KubeJS”所支持的配方,将所有ingot下所有金属(此处为copper铜,bronze青铜,tin锡)在各个配方中锭/粒/块产物(只要有正确的标签)全部设为mod的(此处为mekanism)。
读者可以修改“ingots”内的金属类型,以及“mod”的模组id,来实现自己想要的简单矿辞统一。
注意:有的mod的命名规则不一样。同样是锡锭有的是ingot_tin,有的是tin_ingot,需要根据实际情况对脚本略作修改。
onEvent('recipes', event => {
let ingots = ['copper','bronze','tin']
let mod = 'mekanism'
for (let i of ingots) {
event.replaceOutput({}, `#forge:ingots/${i}`, `${mod}:${i}_ingot`)
event.replaceOutput({}, `#forge:nuggets/${i}`, `${mod}:${i}_nugget`)
event.replaceOutput({}, `#forge:storage_blocks/${i}`, `${mod}:${i}_block`)
}
})
真·世界合成
放在server_scripts文件夹内,该脚本由ChefArug提供。
let removeBlockProperties = (str) => {
if (str.indexOf('[') != -1){
output = str.substring(0, str.indexOf('['))
} else {
output = str
}
return output
}
let getBlockFromKey = (key, object) => {
let block = ''
if (key in object) {
block = object[key]
} else {
block = 'minecraft:air'
}
return block
}
let getBlockFromIndex = (shape, key, index) => {
let output = ''
for (let i of shape) {
output = '' + output + i
}
return getBlockFromKey(output[index], key)
}
let getPosFromIndex = (shape, click_index) => {
let total_length = 0
for (let i in shape) {
if (total_length + shape[i].length > click_index) {
return {
x: +i, //This kept being a string. No idea why, but + forces it to int! (If its a string it SERIOUSLY messes up addition, concating anyone?)
z: click_index - total_length
}
} else {
total_length = total_length + shape[i].length
}
}
//We will only get here if it never returns anything. That means somethings wrong!
console.error(`Recipe loading for a multiblock recipe failed! It appears that index of ${click_index} is outside the structure!`)
return null
}
global.debug = false //Change this to true to show some additional output useful for debugging recipes not working. Shouldn't be used for normal gameplay cause logspam
global.multiblockCraft = (output, output_count, shape, key, click_item, click_index) => {
onEvent('block.right_click', event => {
if (event.hand == 'MAIN_HAND' && event.player.getHeldItem(event.hand) == click_item) {
event.entity.swingArm(event.hand)//This doesn't work as of writing this, but should be fixed soon
let index_pos = getPosFromIndex(shape, click_index)
let corner = {
x: event.block.x - index_pos.x,
y: event.block.y,
z: event.block.z - index_pos.z
}
let current_index = -1
let current_check = {}
let current_rel_pos = {}
let validate_structure = true
let all_pos = []
//Let the validation begin!
for (s of shape) {
for (i of s) {
current_index ++
current_rel_pos = getPosFromIndex(shape, current_index)
current_check = {
x: 0 + corner.x + current_rel_pos.x,
y: corner.y,
z: corner.z + current_rel_pos.z
}
let expected = getBlockFromIndex(shape, key, current_index).toString()
let block = removeBlockProperties(event.world.getBlock(current_check.x, current_check.y, current_check.z).toString())
if (global.debug) {
console.log(`${block}, ${expected}, ${validate_structure}`)
}
if (block == expected && validate_structure) {
all_pos.push(current_check)
} else {
if (global.debug && validate_structure) {
console.log(`Incorrect block found at ${current_check.x}, ${current_check.y}, ${current_check.z} for output ${output}. Expected: '${expected}' but found '${block}' instead`)
}
validate_structure = false
}
}
}
if (validate_structure) {
for (i of all_pos) {
event.server.runCommandSilent(`setblock ${i.x} ${i.y} ${i.z} minecraft:air`)
}
event.server.runCommandSilent(`summon minecraft:item ${event.block.x} ${event.block.y + 0.7} ${event.block.z} {PickupDelay:10,Motion:[0.0,0.2,0.0],Item:{id:"${output}",Count:${output_count}b}}`)
if (!event.player.isCreativeMode()){
event.item.setCount(event.item.getCount() - 1)
}
event.server.runCommandSilent(`particle minecraft:spit ${event.block.x} ${event.block.y + 0.2} ${event.block.z} ${shape.length * 0.2} 0.4 0.4 ${shape[0].length * 0.2} ${current_index * 10}`)
}
}
})
}
//Centred click_index cheat sheet: 1x1: 0, 3x3: 4, 5x5: 12, 7x7: 24. Formula: (total blocks -1) / 2. Remember, the first thing is 0!
global.multiblockCraft('minecraft:diamond', 2, [ //global是必要的,以便在该脚本文件之外也能调用。如果仅限该脚本文件内,global也可以去掉,换成const。
//最顶上一行是世界的最西方向。
'CCC',
'CCC',
'CCC'
], {
C: 'minecraft:coal_block',
},
'minecraft:diamond', 4
)
在最后一段中,第一个'minecraft:diamond'表示产物钻石,“2”表示产物的数量是2,“C”表示不同的方块(如同有序合成配方),第二个'minecraft:diamond'表示激活这个配方需要的物品,“4”表示摆出结构的尺寸(1x1: 0, 3x3: 4, 5x5: 12, 7x7: 24)。
即,用煤炭块在地上摆出3*3的形状,接着用钻石右击正中间的煤炭块。
地上变出了两个钻石。
自制“大师球”
放在server_scripts文件夹内,该脚本由ChefArug提供。
读者可自行将captureItem和capturedItem改成任意物品,比如自己通过CoT或KubeJS添加的物品。
const captureItem = 'minecraft:diamond'//将钻石定为空的捕捉道具
const capturedItem = {name:'minecraft:emerald',displayName:'Soul Emerald'}//将绿宝石定为已捕获到生物的捕捉道具
//因为是英文所以有“a”和“an”之分
const pronounTest = (s,c) => {
if (c) {
return ''
} else if (/[AEIOU].*/.test(s)) {
return 'an '
} else {
return 'a '
}
}
onEvent('item.right_click', event => {
if (event.item.id === capturedItem.name) {
event.server.runCommandSilent(`summon ${event.item.nbt.CapturedEntity} ${event.player.x} ${event.player.y + 0.7} ${event.player.z} ${event.item.nbt.CapturedData}`)
event.item.count --
}
})
onEvent('item.entity_interact', event => {
if (event.item.id === captureItem && !event.target.player && event.target.type != 'minecraft:ender_dragon') { //末影龙除外,你可以添加其他禁止实体
let nbt = event.target.fullNBT
delete nbt.UUID
event.server.runCommandSilent(`summon minecraft:item ${event.target.x} ${event.target.y} ${event.target.z} {PickupDelay:10,Motion:[0.0,0.2,0.0],Item:{id:"${capturedItem.name}",Count:1b,tag:{display:{Name:'{"text":"${capturedItem.displayName}","italic":false}',Lore:['{"text":"Contains the soul of ${pronounTest(event.target.name, nbt.CustomName)}${event.target.name}"}']},CapturedEntity: "${event.target.type}", CapturedData: ${nbt}}}}`)
event.target.y = -400
event.target.health = 1 //并不立刻杀死,以免出现死亡动画。
}
})
实质是把原来的生物丢进虚空,同时记录其全部nbt,再召唤出来一只一样的,早已不是同一只了。
不过这个脚本有个缺陷:被驯养的生物是会有死亡信息的。
所以我个人采用的方法是:暂时关闭死亡信息。掩耳盗铃
event.server.runCommandSilent(`gamerule showDeathMessages false`)
event.target.y=-400
event.target.kill()
event.server.runCommandSilent(`gamerule showDeathMessages true`)
按键显示信息
放在client_scripts文件夹内,由Lady Lexxie提供。
按住shift显示tooltip,并且可以设置每一行的颜色。
onEvent('item.tooltip', e => {
e.addAdvanced('kubejs:test_item', (item, advanced, text) => {
if (!e.isShift()) {
text.add(1, [Text.of('Hold ').gold(), Text.of('Shift ').yellow(), Text.of('to see more info.').gold()])
}
if (e.isShift()) {
text.add(1, [Text.of('Default: '), Text.of('50 '), Text.of('mB/t')])
text.add(2, [Text.of('Basic: '), Text.of('100 '), Text.of('mB/t')])
text.add(3, [Text.of('Improved: ').gold(), Text.of('500 ').yellow(), Text.of('mB/t').gold()])
text.add(4, [Text.of('Advanced: ').darkAqua(), Text.of('2,000 ').aqua(), Text.of('mB/t').darkAqua()])
text.add(5, [Text.of('Ultimate: ').darkGray(), Text.of('10,000 ').gray(), Text.of('mB/t').darkGray()])
text.add(6, [Text.of('Infinity: ').darkPurple(), Text.of('2,147,483,647 ').lightPurple(), Text.of('mB/t').darkPurple()])
}
})
})
效果如图:
复刻罐中奶牛
放在server_scripts文件夹内,该脚本由ChefArug提供。
let anvilSquashingRecipes={};let squashed=[]
const addSquash=(o,e,i)=>{
if (!anvilSquashingRecipes[e]) anvilSquashingRecipes[e]={}
anvilSquashingRecipes[e][i] = o
}
const addSquashingRecipe = (output, entity, input) => {
//typeof an array is object, not array
if (typeof entity == 'object') {
if (typeof input == 'object') {//both plural
for (e of entity) {
for (i of input) {
addSquash(output, e, i)
}
}
}else{//entity plural, input singular
for (e of entity) {
addSquash(output, e, input)
}
}
}else{
if (typeof input == 'object') {//entity singular, input plural
for (i of input) {
addSquash(output, entity, i)
}
}else{//both singular
addSquash(output, entity, input)
}
}
}
onEvent('entity.attack',e=> {
let block=e.entity.block.down;let type=e.entity.type
if (e.source.type === 'anvil'
&& anvilSquashingRecipes[type]
&& anvilSquashingRecipes[type][block.id]) {
block.set(anvilSquashingRecipes[type][block.id])
squashed.push(e.entity.id)
e.entity.kill()
}
})
onEvent('entity.drops',e=>{
let index = squashed.indexOf(e.entity.id)
if (index > -1) {
squashed.splice(index, 1)
e.cancel()
}
})
//例:用铁砧将牛压进冰中变成雪
addSquashingRecipe('minecraft:snow_block', 'minecraft:cow', 'minecraft:ice')
值得一提的是这个脚本可以做出一些更有意思的变动,比如将e.source.type === 'anvil'中的anvil(铁砧)可以改成其他伤害来源,比如机械动力的动力锯create.mechanical_saw。以及let block=e.entity.block.down;这句,可以将.down去掉,就成了目标实体所在的方块而不是其脚下方块。
于是可以有:addSquashingRecipe('minecraft:skeleton_skull', 'minecraft:skeleton', 'minecraft:air')
当骷髅受到动力锯的伤害时,在其所在位置生成一个骷髅头(可以在生成骷髅头颅后,将骷髅传送到虚空kill掉,免得反复掉头)。
更多内容敬请期待,也欢迎社区补充指正。