• 欢迎 游客 来到 CBerGit 我的世界命令托管与研发交流站。 发布您的指令作品、指令思路。
  • 我们正在 招募运维人员 了解详情

服务器命令 1CB 菜单的制作教程及程序自动生成JSON

适用版本
BE 1.16.100.55+
版权类型
原创
官网
https://github.com/Happy2018new/Code-To-MCRawtext_Translate_Json
项目版本
Alpha(10.7)
CB(命令方块)数量
1

引入​

你有听说过——只用 1 个命令方块,就可以显示多种多样的菜单吗?
举个例子,当玩家在计分板 A 的分数为 1 的时候,显示字符串 M
当玩家在计分板 A 的分数为 2 的时候,显示字符串 N
当玩家在计分板 A 的分数为 3 的时候,显示字符串 K

上述的这个例子可以使用命令 TellrawTitleraw 命令实现。
为了简便,本文以 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 怎么说的~

1662807858977.png

可以发现,我们这里用到了 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 组件在仅指定 objectivename 时也可以达到目的。

教程​

这里只讲述如何书写 <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 中的 %%nn 的取值范围是 19 之间的整数。
因此,一个 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..
当然这样看可能不好理解,我们需要『数形结合』。
画个数轴吧!

1662811965178.png

这里没画正方向,所以说一下正方向是向右的,实际上你应该也能看出来。
那么我们要解决的问题就是,当分数是图中红色部分的整数的时候,就解析成功,如果是绿色部分,就解析失败。
因此如果我们反选所有的绿色部分,排除掉它们,那么剩下的就是红色部分的了,也就是我们要的东西了。
补充一下,绿色部分在数学上表示取 [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 网站可能需要进行『科学上网』。
 
最后编辑: