第六十章 基岩版的JSON文本(破200收藏纪念)
JSON文本在Java版很常用。在基岩版虽然能用的地方少了很多,但仍然很有用处。
基岩版的JSON文本主要用于指令、书与笔的文本和告示牌的文本上。由于基岩版指令的限制,我们只能在/tellraw和/titleraw两个指令中用到JSON文本。虽然能用的地方极其少,我们仍然得学习学习,就因为/tellraw这条指令极其有用。
基岩版的JSON文本的基础格式如下:
{“rawtext“:[]}
在基岩版中,每串JSON文本的最外层必然是rawtext组件。rawtext的值是JSON对象列表,也就是由多个JSON对象组成的列表。你可以把JSON对象看作是NBT中的复合标签(两者其实没多大差别),方便理解。
基岩版的JSON文本组件相比Java版要少许多。不算rawtext的话,基岩版一共只有五个组件:
\\内容组件\\
text(值:文本)
selector(值:文本)
translate(值:文本)
score(值:JSON对象,相当于NBT的复合标签)
\ranslate配套组件\\
with(值:由多个文本组成的列表)
最基础的组件还是text,用法和Java版的一模一样:
{“rawtext“:[{“text“:“Hello!“}]}
这解析后会变成:Hello!
你有没有注意到,基岩版甚至连文本颜色格式组件都被阉割了,也就是说我们无法使用color组件来修改文字颜色。既然我们无法使用color之类的组件,那么我们该如何修改文本的颜色和格式?
你是不是忘记了一个东西:§
由于基岩版可以自由使用§来修改文本的颜色和格式,因此Mojang就把color之类的文本颜色格式组件给切了。
在基岩版的JSON文本中使用§,需要注意两点:
①§必须要放在内容组件的值中,不能放在组件名等其他地方。虽然放在其他地方在命令方块中也会生效,但JSON文本就无法被游戏正确识别并输出了。
②使用§后记得要及时用§r来重置文字样式,不然会把§右边的所有文本都修改了样式。比如:
{“rawtext“:[{“text“:“§eHello!“},{“text“:“Minecraft“}]}
这将会输出:Hello!Minecraft(都是黄色)
如果是{“rawtext“:[{“text“:“§eHello!§r“},{“text“:“Minecraft“}]},则只会把“Hello!”一段变成黄色。
selector组件可以输出实体名称,其值必须填的是目标选择器。比如:
{“rawtext“:[{“selector“:“@br /“}]}
这将会输出距离执行地点最近玩家的名称。假设距离执行地点最近的玩家叫做『Phigros』,那么这将会输出:Phigros
selector的使用还是很简单的。但请注意,你不能把selector当做text一样使用。原因很简单:其值必须是个目标选择器。
如果你把selector当做text一样用,比如这样子填写:
{“rawtext“:[{“selector“:“HelloMinecraft“}]}
你会惊奇地发现执行指令后,没有任何的文本输出,也没有任何的报错信息。
这是为什么呢?因为selector的值必须是个目标选择器,你这样填就相当于要输出玩家HelloMinecraft的名称,而游戏中又没有叫做HelloMinecraft的玩家,自然就不会输出。但如果真的有一个叫做HelloMinecraft的玩家且在线,就会正常输出『HelloMinecraft』。
translate组件是这五个组件中最难的一个,因为它有些涉及到Minecraft的模组、资源包开发。为何这么说?因为translate组件可以让一段文字以目标玩家的语言输出。
在学习translate的用法之前,我们要了解一个东西:本地化键(也称『翻译识别符』)
每一种语言都有自己对应的语言文件,比如美式英语对应的就是en_us.lang,中文简体对应的就是zh_cn.lang。游戏中同一个地方的文本会翻译成不同的语言。这时候问题来了:我们该如何在不同的语言文件中正确找到用于这个地方的文本呢?
这时候本地化键就出场了。
把一个地方的文本在不同语言中的翻译都绑定到一串不变的ID上,根据ID找到对应的翻译文本,不就解决这个问题了吗?
举个例子,在下面两个不同的语言文件中分别有这么一行:
en_us.lang:
server.helbr /.getgold=You can get gold by selling items and br /laying games.For exambr /le, you may get 500 coins if you win a game of Bed War.#
zh_cn.lang:
server.helbr /.getgold=您可以通过售卖物品、玩小游戏来获得金币。比如当你赢得一局起床战争时,您可能会获得500枚金币。#
我们只需要在需要用到这一串文本的地方放上『server.helbr /.getgold』,游戏就会自动根据不同的语言将这一串本地化键替换成对应语言的文本。
JSON文本内的translate组件就是干这行的。在translate的值内写上本地化键,游戏就会根据不同的语言将对应的内容呈现出来。比如:
{“rawtext“:[{“translate“:“server.helbr /.getgold“}]}
如果你使用的是中文简体,最终这将会输出:『您可以通过售卖物品、玩小游戏来获得金币。比如当您赢得一局起床战争时,你可能会获得500枚金币。』
如果你使用的是美式英语,这反而会输出:『You can get gold by selling items and br /laying games.For exambr /le, you may get 500 coins if you win a game of Bed War.』
现在你明白了吗?
(注:上面这个server.helbr /.getgold本地化键是编的,但接下来的几个本地化键都是真实存在于游戏中的。)
translate的使用肯定没有这么简单,这只是最基础的用法而已。有时候,本地化键对应的文本内会有一些特殊的部分。比如『death.attack.onFire』,如果你只是这么用它:
{“rawtext“:[{“translate“:“death.attack.onFire“}]}
最终它会输出:
%1$s 被烧死了
这是怎么回事?因为我们没有指定死亡的东西是什么。如果我们要指定,就得用到translate的配套组件:with
with的值是由多个文本组成的列表。至于为什么是个列表,是因为有些时候会有多个特殊的部分,这时候就需要使用列表来分别指定每个部分是什么。
我们待会再研究具有多个特殊部分的情况。先来试试使用with指定死亡的东西是『张三』:
{“rawtext“:[{“translate“:“death.attack.onFire“,“with“:[“张三“]}]}
这将会输出:张三被烧死了
现在我们再来看看有多个特殊部分的情况:
{“rawtext“:[{“translate“:“death.attack.arrow.item“}]}
这将会输出:%1$s 被%2$s 用%3$s 射杀
这句话虽然很短,但有三个特殊的部分。如何正确指定这三个特殊部分呢?按照从左到右的顺序指定:
{“rawtext“:[{“translate“:“death.attack.arrow.item“,“with“:[“枯藤“,“老树“,“昏鸦“]}]}
这会输出:枯藤被老树用昏鸦射杀
一般情况下,特殊部分会按照从左到右的顺序一一对应列表内的元素。在上面的例子中,%1$s最靠左,“枯藤”也在列表的最左边,因此%1$s就被“枯藤”替换了。剩下的%2$s和%3$s同理。
这就是translate组件一般的用法。除了这个用法外,translate还能被当做text组件一样用,且比text组件多出了一个没啥用的功能:自定义特殊部分
特殊部分有两种自定义的格式:
%%s
%%#(#为列表内元素从左到右排列的序号)
先来说说%%s。%%s的用法和上面的%1$s、%2$s之类的一模一样,都是从左到右一一对应。比如:
{“rawtext“:[{“translate“:“你好%%s!这里有一些关于%%s的说明。“,“with“:[“新手“,“空岛战争“]}]}
这会输出:你好新手!这里有一些关于空岛战争的说明。
%%#的功能和%%s比较不一样。%%#的#实际上是列表内各个元素从左到右的排列数字。比如%%1在上面的列表中就代表着『新手』。也就是说,如果这样子填写:
{“rawtext“:[{“translate“:“你好%%1!这里有一些关于%%1的说明。“,“with“:[“新手“,“空岛战争“]}]}
最终会输出:你好新手!这里有一些关于新手的说明。
上面的例子中,%%s和%%#都是独立使用。如果两者一起使用会发生什么呢?
来看看下面这个例子:
{“rawtext“:[{“translate“:“欢迎来到%%s,%%1!您今日的%%s还未领取!“,“with“:[“EaseCation“,“每日签到奖励“,“一个普通的路人“]}]}
猜一猜,最终这会输出什么?
你是不是以为,最终这会输出:欢迎来到EaseCation,EaseCation!您今日的每日签到奖励还未领取!
如果你这样想,就错了。实际上输出的是:欢迎来到EaseCation,一个普通的路人!您今日的每日签到奖励还未领取!
这是怎么一回事?当%%s和%%#一起使用的时候,游戏会优先把%%s替换掉。按照从左到右的原则,第一个%%s被替换成了『EaseCation』,第二个%%s被替换成了『每日签到奖励』。然后游戏才会替换%%#。这时候神奇的地方来了,由于%%s使用过的列表元素%%#就不能再使用,因此%%#的顺序得从第三个元素开始算起,最终导致%%1被替换成了『一个普通的路人』。
这就是translate和其配套with组件的全部内容,你学会了吗?
最后的score组件简单且有用,它可以显示记分板上的分数。
score的值是JSON对象,你可以把它当做是复合标签。对象内有三个子组件:
name——选择正在被记分板追踪的目标,显示ta的分数,值为文本。必须填写目标选择器或玩家名(假的也可以)。
objective——计分项名称。值为文本。
value[可选]——值为文本。如果指定了该项,不管真实的分数是多少,都会显示为该项的值。
(注:作者实验时发现value组件没用,可能在目前的基岩版最新版中已经删去了该标签。作者实验的版本是基岩版1.18.2)
举个例子。假设玩家Liben在计分项Primogems上的分数为2431,我们可以这样输出他的分数:
{“rawtext“:[{“score“:{“name“:“Liben“,“objective“:“Primogems“}}]}
这将会输出:2431
需要注意,当name选定的目标为多个时,游戏将会按照目标选择器排列的顺序输出每个目标的分数。
现在你会使用基岩版的JSON文本了吗?注意,一个JSON对象内不能有多个内容组件。当一个对象内有多个内容组件时,权重高的组件的内容将会覆盖权重低的组件。四个内容组件的权重如下:
score<selector<text<translate
(注:该权重为作者实验得出)
这就是基岩版JSON文本的全部内容了。