引入
你有听说过——只用 1
个命令方块,就可以显示多种多样的菜单吗?举个例子,当玩家在计分板
A
的分数为 1
的时候,显示字符串 M
,当玩家在计分板
A
的分数为 2
的时候,显示字符串 N
,当玩家在计分板
A
的分数为 3
的时候,显示字符串 K
。上述的这个例子可以使用命令
Tellraw
或 Titleraw
命令实现。为了简便,本文以
Tellraw
命令为例展开。众所周知,
Tellraw
命令的语法是 Tellraw <target: target> <raw json message: json>
实际上,我们只需要关心
<raw json message: json>
部分,因为只有它会决定最终的显示内容。那么我就不卖关子了,直接来看这部分的
JSON
形式吧~
JSON:
{
"rawtext":
[
{
"translate":"%%4",
"with":
{
"rawtext":
[
{"selector":"@s[scores={A=1}]"},
{"selector":"@s[scores={A=1..2}]"},
{"selector":"@s[scores={A=1..3}]"},
{"text":"M"},
{"text":"N"},
{"text":"K"}
]
}
}
]
}
来来来,我们先看看
Wiki
怎么说的~
可以发现,我们这里用到了
translate
这个东西,而其后所跟着的则是 with
。那么这里就告诉各位,
translate
中的 %%n
用于指代 with
数组(或复合标签)中的第 n
个元素。举个例子,
{"translate":"%%2",with:["Steve","Alex","Happy2018new"]}
则代表打印出 with
数组中的第 2
个元素,因此显示为 Alex
。但它真的是打印
with
数组(或复合标签)中的第 n
个元素吗?我们需要深刻它的『实际原理』才行了。
实际原理
我们首先要介绍一个概念,即 列表
。在
Python
中,一个列表内的元素可以是各种数据类型的,例如 [2,3,4,'114514']
就是一个合法的列表。那么通过上文我们知道,
translate
中的 %%n
会被替换为 with
中的某一项,而通常情况下是第 n
项。为了方便,我们把
with
数组(或复合标签)内的所有元素提取出来,写到一个列表内。以上文的例子为例,我们得到了一个这样的列表:[ @s[scores={A=1}] , @s[scores={A=1..2}] , @s[scores={A=1..3}] , 'M' , 'N' , 'K' ]
那么在实际执行指令的时候,实际的列表并不是它。因为我们知道,
selector
组件会将 目标选择器
解析为对应的 实体名
,因此如果 命令执行者
的名字是 Steve
且其在 A
计分板的分数是 1
的话,那么游戏会最终解析为这样的一个列表:[ 'Steve' , 'Steve' , 'Steve' , 'M' , 'N' , 'K' ]
为了方便,我们称这个列表是“新列表”。
此时,再将
translate
中的 %%n
替换为这个新列表的第 n
项。上文的例子是
%%4
,所以最终会显示新列表的第 4
项,即 M
。但是,如果
命令执行者
的名字是 Steve
且其在 A
计分板的分数是 2
的话,情况就不一样了。我们再看看预设好的列表:
[ @s[scores={A=1}] , @s[scores={A=1..2}] , @s[scores={A=1..3}] , 'M' , 'N' , 'K' ]
但是我们不难发现,此时第
1
个元素会解析失败,所以最终获得的新列表是这样的:[ 'Steve' , 'Steve' , 'M' , 'N' , 'K' ]
此时,再将
translate
中的 %%4
替换为这个新列表的第 4
项,所以最终会显示 N
了。那么,如果分数是
3
的话,那么原本的 @s[scores={A=1}]
和 @s[scores={A=1..2}]
会解析失败。于是最终获得的新列表就变成了:
[ 'Steve' , 'M' , 'N' , 'K' ]
此时,再将
translate
中的 %%4
替换为这个新列表的第 4
项,所以最终会显示 K
了。于是我们知道了,原先预设好的列表(需要注意的是,它不一定是列表,也可能是复合标签。这里这么说只是为了方便理解罢了)并不是游戏最终解析得到的列表。
只有当对应的元素解析成功时,才会作为一个有效元素放入到列表,并成为新列表的一部分。
除了
selector
组件可以充当这个功能以外, score
组件在仅指定 objective
和 name
时也可以达到目的。教程
这里只讲述如何书写 <raw json message: json>
部分对应的 JSON
。对于其他部分,我想你应该可以实践出来吧~根据上文中 引入 部分给出的例子,我们可以得到一个规律。
如果要显示
4
个不同的内容,且分别对应 4
个不同的显示条件(分数条件),则至少需要向 with
复合标签的 rawtext
部分填入至少 8
个元素。同时,前
4
个元素是显示条件(分数条件),后 4
个元素是显示内容。那么如何安排前
4
个条件,才能达到目的?我们不妨假设预先设计好的列表长成这样:
[ 为分数A时解析成功 , 为分数A或分数B时解析成功 , 为分数A或分数B或分数C时解析成功 , 为分数A或分数B或分数C或分数D时解析成功 , 为分数A时对应的显示内容 , 为分数B时对应的显示内容 , 为分数C时对应的显示内容 , 为分数D时对应的显示内容 ]
那么我们来推导一下。如果是显示第
5
项的话——如果是分数A,则整个列表全部能被解析,最终显示
为分数A时对应的显示内容
如果是分数B,则第一项解析失败,最终显示
为分数B时对应的显示内容
如果是分数C,那么前两项解析失败,最终显示
为分数C时对应的显示内容
如果是分数D,那么前三项解析失败,最终显示
为分数D时对应的显示内容
如果分数不是A、B、C和D,那么前四项都解析失败,最终什么都不会显示了。
因此我们总结得到了一个规律,第
n
个条件如果能被解析成功,那么其后续的所有条件也必须解析成功。值得注意的是,
translate
中的 %%n
的 n
的取值范围是 1
到 9
之间的整数。因此,一个
with
数组(或复合标签)内最多放置 9
个元素,即最多设置 4
个显示内容及对应的显示条件。那有没有解决办法呢?
肯定是有的吖!你可以通过『嵌套』来显示更多的元素。
看看这个例子吧:
a=1..2时显示A | a=233..236时显示B | a=-173..-16时显示C | a=4时显示D | a=5时显示E
那么我们首先写前
3
组。根据前面的结论”第
n
个条件如果能被解析成功,那么其后续的所有条件也必须解析成功”,我们有:第一项元素是
@s[scores={a=1..2}]
第二项元素是
@s[scores={a=!..0,a=!3..232,a=!237..}]
第二项元素为什么长这样呢?我们知道,
scores
利用 ,
来连接参数,而这些参数是同时生效的。因此,只要对这些参数全部进行反选,我们就可以实现诸如
选中满足 条件x 或 条件y 或 条件z 的实体
的效果。第二项元素的条件是
a=1..2 或 a=233..236
那么也可以写为
不是a=..0 且 不是a=3..232 且 不是 237..
当然这样看可能不好理解,我们需要『数形结合』。
画个数轴吧!

这里没画正方向,所以说一下正方向是向右的,实际上你应该也能看出来。
那么我们要解决的问题就是,当分数是图中红色部分的整数的时候,就解析成功,如果是绿色部分,就解析失败。
因此如果我们反选所有的绿色部分,排除掉它们,那么剩下的就是红色部分的了,也就是我们要的东西了。
补充一下,绿色部分在数学上表示取
[1,2]∪[233,236]
关于全集 [-2147483648,2147483647]
的补集。然后,再把得到集合(绿色部分)取一次补集,就得到了红色部分了。需要注意的是,这里都只是在整数范围内讨论的。因此通过『数形结合』,我们可以很快的写出第三个元素。
所以第三项元素是
@s[scores={a=!..-174,a=!-15..0,a=!3..232,a=!237..}]
根据前面总结的规律,我们知道,一个
with
数组(或复合标签)最多可能塞 9
个元素,也就是 4
组分数条件及对应的显示内容。我们再来看看我们的题目:
a=1..2时显示A | a=233..236时显示B | a=-173..-16时显示C | a=4时显示D | a=5时显示E
很显然,我们现在得在第四个元素写入上述所有分数条件,然后让第五个元素是A,第六个元素是B,第七个元素是C,第八个元素是一个
复合标签
,而这个复合标签囊括剩下的 a=4时显示D | a=5时显示E
。所以,第四项元素是
@s[scores={a=!..-174,a=!-15..0,a=!3,a=!6..232,a=!237..}]
然后现在要嵌套了。在新嵌套的复合标签内只有两个条件了:
a=4时显示D | a=5时显示E
因此有——
嵌套内的第一项元素
@s[scores={a=4}]
嵌套内的第二项元素
@s[scores={a=4..5}]
嵌套内的第四项元素
D
嵌套内的第五项元素
E
不过你可以写成
嵌套内的第一项元素
@s[scores={a=!..-174,a=!-15..0,a=!3,a=!5,a=!6..232,a=!237..}]
嵌套内的第二项元素
@s[scores={a=!..-174,a=!-15..0,a=!3,a=!6..232,a=!237..}]
嵌套内的第四项元素
D
嵌套内的第五项元素
E
那么写成
JSON
就是这样了。
JSON:
{
"rawtext":
[
{
"translate":"%%5",
"with":
{
"rawtext":
[
{"selector":"@s[scores={a=1..2}]"},
{"selector":"@s[scores={a=!..0,a=!3..232,a=!237..}]"},
{"selector":"@s[scores={a=!..-174,a=!-15..0,a=!3..232,a=!237..}]"},
{"selector":"@s[scores={a=!..-174,a=!-15..0,a=!3,a=!6..232,a=!237..}]"},
{"text":"A"},
{"text":"B"},
{"text":"C"},
{
"rawtext":
[
{
"translate":"%%3",
"with":
{
"rawtext":
[
{"selector":"@s[scores={a=!..-174,a=!-15..0,a=!3,a=!5,a=!6..232,a=!237..}]"},
{"selector":"@s[scores={a=!..-174,a=!-15..0,a=!3,a=!6..232,a=!237..}]"},
{"text":"D"},
{"text":"E"}
]
}
}
]
}
]
}
}
]
}
JSON
应当压缩,不然太长了。你可以在 这里 压缩
JSON
。程序自动生成JSON
很显然,人类的脑子是不够用的。对于大型的菜单,我们不可能每次都画图解决,这太麻烦了,而且也很容易产生很多的 BUG
,也不便于排查错误,这样开发起来是低效的。那么,聪明的人类既然会造洗衣机来洗衣服,而不用手搓的话,那么我们也可以做一个程序,输入计分板、显示条件(分数条件)及对应的显示内容,然后自动生成
JSON
就可以啦!当然,我已经完成了这个程序了。我依然使用
JSON
,但我把它看作一种『伪代码』形式。我写了一个例子,是用
JSON
写成的 伪代码
,你可以在 此处 看到。我的程序放在
Github
上的,链接在这 Happy2018new/Code-To-MCRawtext_Translate_Json相关的使用说明在 README.md 处,您可以自行查阅。
我是一个
Python
语言的初学者,所以难免写的程序有点 Bug
,所以遇到了什么漏洞,请在 这里 反馈哟~值得说明的是,部分用户前往
Github
网站可能需要进行『科学上网』。
最后编辑: