命令方块
用途简介
命令方块(Command Block, 简写: CB)就是一种能设置命令, 在激活时执行命令的方块。
命令方块不能在任何模式获得(包括创造模式的背包也没有), 只能透过命令给予物品/放置。
常用命令: /give @p command_block
命令方块执行命令与玩家/实体执行类似, 也会储存命令执行统计。
然而某些默认针对执行玩家的命令(如/clear)在命令方块执行时必须指定执行玩家,否则无效。
命令方块执行命令可以避免人手输入的麻烦。(当然, 第一次你还是得人手输入, 除非是OOC)
也能在短时间执行大量命令, 比如在1 gt内执行上千条命令。
有三种命令方块:脉冲命令方块(Impulse Command Block, 简写: ICB), 链锁命令方块(Chain Command Block, 简写: CCB), 及循环命令方块(Repeating Command Block, 简写: RCB)。
三种命令方块各有好处, 并能够在命令方块的GUI里切换模式, 不需要独立获取别的命令方块物品。
计划刻
计划刻其实就是一个列表, 里面储存着命令方块的坐标。
比如有3个命令方块, 我依次激活a、b、c, 列表就会依次储存a, b, c。
然后下一个游戏刻的时候, mc就会根据计划刻里的位置, 依次执行a, b, c里的命令。
三种命令方块
概念澄清: 激活≠执行。
激活是命令方块收到红石信号/从auto:0b变为auto:1b的时候。
执行是命令方块执行命令的时候。
从时间的角度来看, 两者也是相差1gt的(激活后1gt才执行)
脉冲命令方块
脉冲命令方块(Impulse Command Block, 简写: ICB)被激活之后1gt会尝试执行里面的命令一次(视乎是否条件制约)。激活的时候也会让指向的链锁命令方块加入计划刻。
注意: ICB在本gt会否执行命令是看前1gt有没有被激活而不是本gt。这和计划刻有关。其运作原理如下。
首先, ICB在被激活的时候, mc会将其坐标加入计划刻。
下一gt的时候, mc会根据计划刻依次让指定坐标的cb执行命令。
注: 这部分为进阶的实验, 需要后面数章的知识才能明白实验的原理。
本实验分别使用了: 目标选择器选择实体的顺序, execute执行的顺序
因此, icb的执行顺序并不是视乎坐标, 而是看激活次序。这个可以透过一个简单的实验证明:
把一串icb排成一行, 每个里面的命令为say (第几个cb), 并放进marker实体(tag=marker)。然后分别在第一个cb和最后的cb的位置执行
execute @e[tag=marker] ~ ~ ~ blockdata ~ ~ ~ {auto:1b}
之后会发现两次的执行顺序刚好相反, 分别是1 2 3 4 5 6...n和n n-1 ... 3 2 1。
链锁命令方块
链锁命令方块(Chain Command Block, 简写: ccb)传统上认为会在接收到来自指向它的命令方块的信号后, 会尝试执行命令并传递信号给指向的链锁命令方块。
然而这看法是错的。
链锁命令方块实际的运作方式比较复杂。我会将整个过程分为两部分: 执行前1gt, 执行时的1gt。
执行前1gt: 在icb/rcb/ccb被加入计划刻时, mc把其指向的ccb加入计划刻, 并重复这过程。
执行时的1gt: mc根据计划刻依次让指定坐标的cb执行命令。
由此可以推断, ccb执行时在后面加入新的ccb是没用的, 因为那些新的ccb没有加入计划刻, 不会自动执行。
然而, ccb执行时即使中间断了, 后面的也能继续执行, 因为mc看的是计划刻而不是"信号"。
此外, ccb在加入计划刻的时候能够在非激活状态, 也就是没有红石信号以及auto:0b。只需要执行时提供红石信号/auto:1b即可让其执行。如果加入计划刻的时候是激活状态, 然而执行时变为非激活状态, 命令也不会执行。
进阶: 我们能够在执行的时候替换ccb, 以达到瞬间调用模组的需求。有两种方法: 使用结构方块放置及clone。然而由于该技术需要的命令特别多(确保不会超出空的执行模块的长度), 而且限制很大(会覆盖掉之后的命令), 因此并没有实际使用。
循环命令方块
循环命令方块(Repeating Command Block, 缩写: rcb)被激活时会把自己加入计划刻, 之后的1gt执行, 执行后检查自己是否激活, 是的话就加入计划刻, 不停循环。
因此, 可以看成被激活时(被激活后1gt开始)会不停执行命令, 速度为每gt一次, 也就是20hz(20次每秒, 理想情况下)
所以, rcb适合使用在高频的系统里。
然而, 这导致了一个问题: 在rcb之后执行的cb如果关掉了rcb, rcb由于计划刻不会删除, 因此还会执行多一次。
因此一些需要检查条件决定是否继续执行的系统, 或许需要使用icb以确保安全。
条件制约
当命令方块是条件制约(conditional, 简写: cond, block states: conditional:true)的时候, 它会检查指着它箭头尾部的命令方块在本gt有没有成功执行命令。
当左边的成功, 右边的也能执行
即使左边的成功, 右边的也不能执行, 因为左边的没有指着右边的cb的箭头尾部
如果本gt指着它箭头尾部的命令方块没有执行过或是执行失败(消失了也不行...), 则不会执行。
避免使用长串的条件制约以模拟if, 以免中间某些命令因某些原因失败导致后面的全部都不能执行。详见基础逻辑中的布尔逻辑运算。
使用条件制约时, 请确保自己清楚里面的命令的成功、失败条件是什么, 以免出现意外情况
自动激活
NBT相关知识请后方NBT章节
自动激活(NBT: auto:1b)就是模拟命令方块被红石激活的状态, 能够激活命令方块。
icb只会在auto从0b转为1b之后1gt执行命令(可以是1gt内先设置为0b然后1b)。rcb就是当auto为1b的时候就会执行命令。ccb则是在检查是否执行的时候检查auto/激活, 只要auto为1b或者被红石激活了就会执行命令(可以在执行前的瞬间激活, 不需要提早1gt)
因此, ccb经常会设置为auto:1b, 因为这比较方便而且能节省空间(ccb能拐弯叠在一起而之间不需要有空隙放置红石块)。
除此以外, 某些系统会以marker定位cb的位置, 并以auto来控制ccb是否执行及icb是否在下1gt执行。
*部分PCB语法介绍
本教程之后的部分可能会使用pcb语法表达系统。这里会讲解几个经常使用的语法。
注释:
//注释
或者是
/*
多行注释
*/
PCB命令
init:命令
在放置模块时执行
after:命令
在放置模块后执行
mark:(marker名称) tag1 tag2 ...
在下一个cb的位置生成一个marker(AreaEffectCloud)
stats:统计 实体选择器 记分板目标
绑定下一个cb的stats到指定实体(可以为marker)
前缀
其他都会视为命令, 放在ccb里。
然而能够通过前缀改变cb的设置。
前缀的写法是: 前缀:命令
同一条命令能够有多个针对cb的前缀, 如 icb:cond:say hi
前缀 | 意义 |
---|---|
icb | 放在icb里 |
rcb | 放在rcb里 |
cond | 当前cb为cond模式 |
PCB例子
//setup scoreboardinit:scoreboard objectives add index dummy//clear previous markersinit:kill @e[tag=array]init:kill @e[tag=loop]//pointerinit:summon AreaEffectCloud ~ ~ ~ {Duration:2147483647,CustomName:EndList,Tags:["array"]}/*要进行的操作:turn.add(Left);for (int i = turn.count-2; i >= 0; i--) {turn.add(! turn[i]);}*///loop(手动, 为了避免爆炸) {
icb:blockdata ~ ~ ~ {auto:0b}/*加物件到list最后:1. EndList +1(本来代表最大的index, 然后+1就空出一个没人用的index)2. 生成AEC, tag=new, 方便之后操作3. 把新生成的AEC的分数设置为EndList的分数4. 把新生成的AEC的new tag删除掉, 因为已经没必要使用了, 留着会影响下一次*///在list的最后加上Left
scoreboard players add @e[name=EndList] index 1
execute @e[name=EndList] ~ ~ ~ summon AreaEffectCloud ~ ~ ~ {CustomName:Left,Tags:["array","new"],Duration:2147483647}
scoreboard players operation @e[tag=new] index = @e[name=EndList] index
scoreboard players tag @e[tag=new] remove new//把list所有元素的index - list长度//结果: -(n-1), -(n-2), -(n-3), ..., 0//之后会慢慢加回去, 直至最小的index为0//从后操作到前
scoreboard players operation @e[tag=array,name=!EndList] index -= @e[name=EndList] index
scoreboard players set @e[name=EndList] index 0//如果有负数则开始for
testfor @e[tag=array,score_index=-1]
cond:execute @e[name=for_loop] ~ ~ ~ blockdata ~ ~ ~ {auto:1b}//for loop (第二大到最小){mark:for_loop loop
icb:blockdata ~ ~ ~ {auto:0b}//全部的index +1//先index+1能避免操作list最后的元素(最后本身index为0, +1后index为1)
scoreboard players add @e[tag=array] index 1//在list的最后加上list[0]的相反
scoreboard players add @e[name=EndList] index 1
execute @e[name=Left,score_index_min=0,score_index=0] ~ ~ ~ execute @e[name=EndList] ~ ~ ~ summon AreaEffectCloud ~ ~ ~ {CustomName:Right,Tags:["array","new"],Duration:2147483647}
execute @e[name=Right,score_index_min=0,score_index=0] ~ ~ ~ execute @e[name=EndList] ~ ~ ~ summon AreaEffectCloud ~ ~ ~ {CustomName:Left,Tags:["array","new"],Duration:2147483647}
scoreboard players operation @e[tag=new] index = @e[name=EndList] index
scoreboard players tag @e[tag=new] remove new//还有负数的话就重新来过
testfor @e[tag=array,score_index=-1]
cond:execute @e[name=for_loop] ~ ~ ~ blockdata ~ ~ ~ {auto:1b}//}//}
*OOC
通过一条命令执行大量命令/放置大量命令方块。能够方便的导入命令到世界里。
这里只会简单的讲解一下其原理。实际做法可以有很多, 也有很多优化的方法。
OOC一般是通过矿车骑矿车骑矿车...一直骑下去(或者是一堆矿车骑着掉落沙), 每个矿车都是命令方块矿车, 而里面有着需要执行的命令, 而最底下是掉落沙状态的红石块和激活铁轨。
OOC是一条summon命令, 上面骑着那么一大堆东西。在生成时, 掉落沙很快会掉到地上变成方块, 而上面的矿车就会掉到方块上, 被激活并执行命令。
OOC充分利用了MC每条命令最多有32767(虽然经常没达到这个极限就炸了)的字数极限, 一次过导入一大堆命令, 很大程度上方便了在文字档案里写命令而不是在MC里直接写的玩家。