这当然不是教程...这只是一系列来自一只话唠的碎碎念。
每条命令都可以看作由一定的成分组构而成。
总能看到认为命令是确定的,我们只需要把它背下来就可以了的人。显然对命令有所了解之后,这样的认知就很容易被颠覆。mc中的命令并不像是某些游戏的作弊码,通过固定的东西来完成固定的效果……相对来说它要灵活很多。
这一章就将会讲述我眼中命令的基本组成,或许不甚严谨,但是也许是一道新世界的大门(笑
2021.12 数据,可能有更多内容
这不是教程§2|命令本体
这当然不是教程...这只是一系列来自一只话唠的碎碎念。
每条命令都可以看作由一定的成分组构而成。
总能看到认为命令是确定的,我们只需要把它背下来就可以了的人。显然对命令有所了解之后,这样的认知就很容易被颠覆。mc中的命令并不像是某些游戏的作弊码,通过固定的东西来完成固定的效果……相对来说它要灵活很多。
这一章就将会讲述我眼中命令的基本组成,或许不甚严谨,但是也许是一道新世界的大门(笑
分类永远有无数种方式,我比较习惯的方式倒是和wiki上相同:首先先分为服务器命令和非服务器限定的命令,非服务器类又按照命令的执行目标将命令分为四大类:玩家 实体 方块和世界。
有些命令或许不会被单独一类所包括,比如/replaceitem就可以利用参数分别对实体和方块生效。这时候它被同时划分进两类。
简单的列张表,结果将会是这个样子……
http://minecraft.gamepedia.com/Commands#Summary_of_commands
命令的表现形式非常直观:由一个固定词语开头,后面跟上可变/可选参数的“句子”。
这些参数和命令名一起构成了完整的命令语句,这使得我们可以通过命令来影响游戏世界中的事件。当然也有些命令不需要参数,bi\\比如/toggledownfall命令,单依靠命令名就可以表达完整的含义……于是在设计上,它没有相应的参数——只靠它自己就够了。
可选和必需
参数一般分为两类,一类是必须填写的,一类是可以省略的。
举个简单的例子,很多人最初接触到的命令是/gamemode,它的表现形式是这样的:
代码:
- /gamemode <模式> [玩家]
其中gamemode是命令名,<模式>是必需参数,[玩家]是可选参数。
很多时候我们都会直接/gamemode 1来结束这条命令。这并没有问题,因为最终写出的这条命令已经全部包含了所有的必需参数。指令的含义已经表达清楚,mc可以理解并执行。在这个例子里,我们让mc做的事情就是“将命令使用者的游戏模式切换为创造模式”。
但有的时候我们并不仅仅想对自己进行模式的操作。我们可能会希望让所有的人都被切换为创造,于是我们写出了另一条命令:/gamemode 1 @a。
在这条命令里,@a就是一个可选的参数。我们不需要加入这个参数也可以表达完整的意思,但是这个参数的加入使得我们表达的意思更加完整,或者说,给命令的效果增加了更多的限制条件。
当一条必需参数缺失的命令被尝试执行时,mc会告诉你“你写的这是什么鬼玩意儿该给的东西都没给”,并且拒绝你的命令。如果必需参数完备,而有可选参数没有填写时,可选参数会按照默认值被补全进最终的执行。也就是说,实际上即使你缺省了参数,mc也不会无视它们——只是他们已经有一个可以代入执行的值了而已。
我想偷懒!我要省参数!
正如前文所述,当一个参数可以被缺省时,mc会用默认值替代它。
没错,每一个被缺省的参数,都有一个默认值。
显然有些参数是无法配给默认值的。比如summon的实体名——你不写清楚,mc怎么知道该给你生成些什么。
而有些参数则是因为位置的原因无法配给默认值——例如setblock的坐标。
你可能说“为什么不像summon一样将坐标放在生成目标之后呢?”
因为setblock有一个更常被缺省的参数:方块数据值。
能被缺省的参数一定放在命令的末尾,因为前面的必需参数之间出现了未可期的空位是不可接受的。
有些命令看起来可以被省略的东西在指令的前段,但实际上,在mc的认知之中,这是两种不同的命令格式,查看help就可以知道这一点。
依旧举个例子。execute命令可以跟一个detect参数,用于监测被execute的目标周围是否有满足要求的方块。非常实用的功能,但显然,未必需要。这时候这个功能往往被做成可选的,只是由于在detect之后并非空无一物——它之后会跟上其他的命令——所以在execute的help中,有无detect是两种命令格式,而不是单纯的参数可选与否。
命令对象
一条命令无论如何都会有自己的执行者和自己作用的目标。执行者不一定是玩家,甚至不一定是实体……比如cb表示“我是个方块”。目标也不一定是实体……比如有些世界操作命令,最后的目标就是level.dat(咦
执行者和目标
执行者和目标组成了命令的对象,在命令之中同样扮演着非常重要的作用。
执行者也就是指令的发出者。每一条命令必然都有且仅有一个执行者。
执行者可以分为几类,各自拥有不同等级的权限:
服务器后台:默认最高权限也就是4级op,可以使用几乎所有的命令……为什么是几乎所有,是因为命令里还有/publish这种奇葩啊(苦笑
服务器内op玩家:根据op等级拥有不同等级的权限。
1级op:仅拥有无视出生点保护的能力
2级op:权限类似于单机环境下的允许作弊,可以使用大部分非服务器命令
3级op:可以使用玩家管理类服务器命令例如/op /ban /kick此类
4级op:可以使用服务器管理类服务器命令例如/save-all /stop
单机/局域网环境下允许作弊玩家:类同于2级op权限,可以使用全部非服务器命令,但是你会发现有些命令其实是需求3级op的比如/debug(
书本/tellraw里的clickEvent事件:等同于玩家在聊天框里执行,根据玩家的权限来判别权限
有些命令格式仅限玩家使用。
命令方块/命令方块矿车:类同于2级op权限,可以使用大部分非服务器命令,使用/help会有彩蛋(?
牌子clickEvent事件:类同于2级op权限,可以使用大部分非服务器命令,list类命令将没有输出
通过execute转移到的执行者(无论是否玩家):类同于2级op权限,可以使用大部分非服务器命令
基本上这就是所有可能的执行者了。简单地说可以分为四类:玩家,实体,cb,牌子。
而目标的种类就繁琐多了。因为命令的目标非常广泛,涉及到对mc世界的各种调整……所以一般按照命令分类方式,分成玩家 实体 方块 世界四大类。
执行者转移
通过一条名叫execute的命令我们可以转移执行者。
这个转移是很完整的,基本可以看做被选中的实体执行了命令。无论是命令执行中的对象获取,还是指令返回值的挂靠,都将以被转移到的目标为准。
举一个很简单的例子好了。
1.10新增了命令/teleport,这条命令和/tp最大的不同就是修改了命令的坐标偏移获取方式:从相对于目标变成了相对于执行者。于是在聊天框执行这两条命令就会得到完全相异的结果:
代码:
- /tp @e ~ ~1 ~
- /teleport @e ~ ~1 ~
前一个是将所有的目标,也就是所有实体,全部tp到比他们原先坐标y+1的位置;而后一条命令,将会将所有的实体,tp到指令执行者也就是你的头上一格……
这并不是一对能够互换的命令,但是可以进行单方面的替换——
代码:
- /execute @e ~ ~ ~ teleport @e[c=1] ~ ~1 ~
上面这条命令就和/tp @e ~ ~1 ~等价。原因很简单,因为在这条命令执行的时候,将会被视为全部的实体对自己执行了一次向上一格的teleport。执行者取代了目标成为坐标偏移的依据,而execute和选择器的配合让每一个执行者都成为了自身的目标。于是,效果就达到了。
上面也提到了这个转移的完整性。execute @e[tag=a] ~ ~ ~ worldborder get是通过stats手段获得边界坐标的常用手法,但这时候这个queryresult的stats应该挂在tag为a的这个实体上,而不再是cb上——cb执行的只是execute,而不是worldborder get。一个execute链中,每一层都视作只执行它的那一层execute,除了最后一层执行最终跟随的命令。
连续的执行者转移
当一个实体在同一个命令中被多次execute时,按照执行解析的顺序来决定最后它会拥有怎么样的结果。例如,现在场上有两个tag为test的实体,在聊天框里执行此命令:
代码:
- execute @e[tag=test] ~ ~ ~ execute @e[tag=test,c=-1] ~ ~ ~ testfor @e[tag=test]
首先被执行到的是execute @e[tag=test] ~ ~ ~这一层。你在这一层收获了2的SuccessCount和2的AffectEntity,执行者转移到两个带有tag的实体身上;
第二步被执行的是execute @e[tag=test,c=-1] ~ ~ ~这一层。这两个实体在这一层收获了……且慢。
mc对execute的执行规则很有意思。如果你看过pca那个execute*4炸电脑的帖子,应该理解难度会小上很多。
为了方便描述,我们给这两个实体分别起个名字:按照选择到的顺序分别叫它们a和b。
这条命令的实际执行逻辑是这样的:
你选择了a和b;a选择了b;b执行了testfor;b选择了a;a执行了testfor。
它就像一棵树,会在每一条链执行结束的时候退回到上一个分支点,然后跟着这一条分支继续执行,直到所有的分支尽数走完为止。
这里附上pca那个帖子http://www.mcbbs.net/thread-630291-1-1.html,可以作为对execute和执行者转移带来影响的深一层思考。
当execute链中任意一环选择不到目标的时候,这一条execute链就会中断。依旧是举例:
代码:
- execute @e[tag=a] ~ ~ ~ execute @e[tag=b,c=1,r=0] ~ ~ ~ ...
一个在检测同一个实体多tag的时候常用到的小手段,实用性还是挺高的。这时候可能被加载的区块里面有不止一个拥有a这个tag的实体,但是由于第二个选择器的目标转移(c=1,r=0一般在不考虑tp的情况下仅会选择到自己),只有当自身拥有tag b的时候,后续的命令才会被执行;如果没有,那么基于这个拥有tag a的实体的execute就中断了,后续命令也就不会发生。但是这并不影响到其它拥有tag a的实体——试想前文树的比喻,你砍断了一根分支,其余的分支依旧健全。
同为命令三要素之一,命令会在执行完毕以后给予执行者一个(堆)返回值:这些值包括了命令成功次数(SuccessCount),影响实体数(AffectEntities),影响方块数(AffectBlocks),影响物品数(AffectItems)和查询结果(QueryResult)。显然并没有命令能同时对方块、实体和物品生效顺带还查询个值……所以一般来说,每条命令对我们有用的返回值只有1-2个,一个永远存在的返回SuccessCount和剩下四个中这条命令目标对应的值。
这个值被返回会有什么作用呢?应该从老时代过来的人都知道比较器可以检测cb是否执行成功,执行成功就会给出一个红石信号输出。实际上,这个输出信号的强度就是由返回值SuccessCount决定的。这个值在cb上被储存于一个nbt里,比较器检测这个nbt然后给出相应的输出。
当然,它远远不止能用做红石信号输出。作为一个值,我们想用它的话……对我相信大家已经想到怎么做了,记分板。
通过/stats命令或者data类命令,我们可以将命令返回值绑定到计分板上,无论是实体还是方块,只要它是一条命令的执行者,你就可以将它绑定到记分板。执行过这样的绑定之后,每当命令被执行,相应的返回值就会被输出到你所绑定的记分板目标上。恩大家都知道我要举例子了对不对……
代码:
- /scoreboard players set 成功次数 success 0(/stats仅在原先记分板内有分数时才能进行有效的绑定)
- /stats entity @p set SuccessCount 成功次数 success
记分板目标创建和显示略去。这两条命令将使在我解除绑定之前,所有命令的SuccessCount返回值更新到假名"成功次数"的success记分板里。此时我执行这条命令:
代码:
- /testfor @e
你应该会看到,我并没有"进行记分板操作",但是这个假名的记分板里面的确有了分数。
这个获取返回值的方式还可以做到很多有趣的事,例如利用/time query的QueryResult获取游戏时间,利用/worldborder get的QueryResult获取边界大小;利用/testfor的SuccessCount来更简单的确认一个实体是否存在;利用/clear的AffectItems判断玩家拥有多少个目标物品;利用/fill的AffectBlocks获取区域内的方块数量……种种用法不胜枚举。
stats相当于给命令的结果和其他命令的条件架了一座桥梁,我们可以根据获取到的结果让系统来判断下一步该怎么做,而不需要人工的干预。
值得注意的是,stats命令的本质是建立一个附着在执行者身上的nbt……也就是说你甚至可以让一个实体刷出来就带着stats,而不需要再一次的绑定。
依旧是欢迎提醒+欢迎纠错,我手抽这种事不是两三次了……
看到这里的人,来,再给你一个抱抱x
但是chyx的goodbye and good luck是什么鬼嘛
gamemode这个指令比较特殊,在对话框里打是可以省略玩家的
但是在命令方块里不行
ksc 发表于 2017-1-25 19:39
省参数那里莫名想起函数重载233333
省参数充其量也就是有默认参数值的参数……
/scoreboard <objectives|players|teams>...倒是有点重载的意思2333