事情的起源是这样的……我正在着手制作圣诞节活动的奖励。按照以往一贯的做法,我会将所有物品的 NBT 保存后,将它们整合到生成村民的命令中,最后将命令交给管理员即可。在原版客户端中,一个严重的问题在于:由于活动奖励使用了彩色的名称和Lore,因此NBT中会出现大量 minecraft 的样式代码 (Formatting Codes)。样式代码以章节符§
为开头,但章节符在原版中无法被复制到聊天框和命令方块中。好在1.12时,一些辅助mod使复制章节符成为了可能,因此曾经的活动奖励制作还较为顺利。
升级到1.13.x时,没有了mod的帮助,制作彩色物品变得更为困难了。在1.13.x中,物品的名称标签终于改为了 JSON 格式,这也意味着为名称添加颜色和样式变得容易了一些。然而物品的 lore 标签依旧为字符串格式,因此仍需要使用样式代码来实现彩色lore。
那么究竟要如何才能让章节符§
出现在1.13.x的原版客户端内呢?问了问 google 之后,我了解到,可以使用转义的方法让章节符出现。Minecraft在NBT的标签中只支持反斜杠\
和引号"
的转义,但在 JSON 中则支持更多的类似\n
和\u
的转义。其中\u
的转义可以使UNICODE代码转化为相应的字符,正是利用这点,我们可以让章节符出现在游戏中。
在Minecraft中,使用 JSON 格式并且支持执行命令的有成书、告示牌、tellraw等等。使用tellraw和成书实现会导致因发送了非法字符§
而被客户端踢出的迷之问题,因此需要使用告示牌来制作。制作的思路为先准备一段带有\u
转义符的命令,把它写入告示牌的 JSON 文本里"clickEvent":{"action":"run_command","value":"/command"}
的字段中。一般为了后续编辑方便,/command
会设置为放置带有命令的命令方块。如果制作正确,在最终放置的命令方块中就会出现正常方法输不进去的样式代码。
这其中最为复杂的部分在于转义的嵌套。这种实现方法会使命令中出现多重的引号,而每出现一重引号,就需要额外嵌套一层转义,因此最终的代码可能会充满了转义符\
。这里直接略过探究的过程,给出带有样式代码的命令方块的具体的制作方法如下:
首先准备一段带有样式代码的命令,例如:
/say §dhi
将其中所有的章节符§
改为对应的UNICODE转义码\\u00a7
。注意这里开头用了两个反斜杠(我也不知道为什么它会需要再转义一次)
/say \\u00a7dhi
之后将这段命令填入下面的命令中:
/setblock ~ ~1 ~ minecraft:sign{Text2:"{\"text\":\"CLICK ME\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/data merge block ~ ~-1 ~ {Command:\\\"REPLACE ME\\\"}\"}}",Text4:"{\"text\":\"\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/setblock ~ ~ ~ minecraft:air\"}}"} replace
再将填入后的命令直接复制粘贴到命令方块即可。运行命令方块后,上方会出现一个木牌。点击木牌将会替换下方命令方块的内容为先前准备的内容,并且带有样式代码。
需要注意的是,如果你准备的命令带有引号,则需要额外对引号进行转义。由于上面的命令中已经有了两次转义,因此你的命令中的第一层引号需要三次转义,而第二层需要四次转义。举个栗子,比如要准备这一段命令:
/give @p enchanted_golden_apple{display: {Lore: ["§5一种神秘莫测的水果, 给予食用者力量。", "§5它有梦幻般的味道……给人留下十分强烈的回忆,", "§5然而只可意会不可言传。", "§e§o\"2018圣诞节\""], Name: "{\"text\":\"§d星之果实\"}"}} 1
注意因为这里的 JSON 文本已经包含了转义符,因此除了对引号进行三次转义,还要对转义符进行三次转义,实际上也就是在它们前面加七个反斜杠(也可以理解为对嵌套的引号进行四次转义)。对这段命令替换章节符后为:
/give @p enchanted_golden_apple{display: {Lore: ["\\u00a75一种神秘莫测的水果, 给予食用者力量。", "\\u00a75它有梦幻般的味道……给人留下十分强烈的回忆,", "\\u00a75然而只可意会不可言传。", "\\u00a7e\\u00a7o\"2018圣诞节\""], Name: "{\"text\":\"\\u00a7d星之果实\"}"}} 1
再对进行引号和转义符的转义(\\u00a7
不需要进行再次转义了):
/give @p enchanted_golden_apple{display: {Lore: [\\\\\\\"\\u00a75一种神秘莫测的水果, 给予食用者力量。\\\\\\\", \\\\\\\"\\u00a75它有梦幻般的味道……给人留下十分强烈的回忆,\\\\\\\", \\\\\\\"\\u00a75然而只可意会不可言传。\\\\\\\", \\\\\\\"\\u00a7e\\u00a7o\\\\\\\\\\\\\\\"2018圣诞节\\\\\\\\\\\\\\\"\\\\\\\"], Name: \\\\\\\"{\\\\\\\\\\\\\\\"text\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\u00a7d星之果实\\\\\\\\\\\\\\\"}\\\\\\\"}} 1
复制到之前的命令里面,最终的命令为:
/setblock ~ ~1 ~ minecraft:sign{Text2:"{\"text\":\"CLICK ME\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/data merge block ~ ~-1 ~ {Command:\\\"/minecraft:give @p enchanted_golden_apple{display: {Lore: [\\\\\\\"\\u00a75一种神秘莫测的水果, 给予食用者力量。\\\\\\\", \\\\\\\"\\u00a75它有梦幻般的味道……给人留下十分强烈的回忆,\\\\\\\", \\\\\\\"\\u00a75然而只可意会不可言传。\\\\\\\", \\\\\\\"\\u00a7e\\u00a7o\\\\\\\\\\\\\\\"2018圣诞节\\\\\\\\\\\\\\\"\\\\\\\"], Name: \\\\\\\"{\\\\\\\\\\\\\\\"text\\\\\\\\\\\\\\\":\\\\\\\\\\\\\\\"\\u00a7d星之果实\\\\\\\\\\\\\\\"}\\\\\\\"}} 1\\\"}\"}}",Text4:"{\"text\":\"\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/setblock ~ ~ ~ minecraft:air\"}}"} replace
你可以尝试开一个单机创造,把它复制到命令方块里去试试看。注意,如果是单机的话,可能需要将命令最前面的minecraft:
去掉
其实我挺想有一个自动转换的小工具,不过网上找了一圈似乎没有找到适用于1.13.x的工具。这个时候就会觉得要是会写代码就好了.jpg