帆窝

浅谈Minecraft Java版中的文本格式化

富文本

Minecraft Wiki有云者,Minecraft通过文本组件向玩家发送和显示富文本。富文本可以显示在Minecraft Java版中的许多地方,例如聊天栏、动作栏、标题、Boss栏……

你可能听说过,曾经的我们使用一种特殊的分节符号§来在文本中添加颜色和格式信息。然而,这种方式已经在Java版中被弃用。文本组件正是一种更现代的富文本数据存储格式,可以被用在数据包和地图制作中,下面首先对其做简单介绍。

本文中的内容均以Minecraft Java版 1.21.10 为准。

数据包中的文本组件

我们在数据包中使用命令编写函数,即一个个后缀为mcfunction的文本文件。在函数(命令)中定义文本组件可以使用SNBT格式,这是一种非常类似于JSON,但不一样的数据存储结构。这里不对SNBT做过多介绍,结构化的代码展示也以JSON格式为主,毕竟它们二者确实很像。

{
  "text": "Hello?",
  "click_event": {
    "action": "run_command",
    "command": "/tp @s 100 100 100"
  }
}

以上JSON定义一个文本组件。这个文本组件显示文本Hello?,如果你将其打印到聊天中,你将可以用鼠标点击这段Hello?,然后将会执行/tp @s 100 100 100指令。

顺便一提,从1.21.6开始,游戏对于大部分这种点击执行命令的情况都做了额外确认。如果你是内容作者并且认为这影响到了你的作品的游玩体验,可以试试芒果的这个模组~(芒果卖瓜ing)

图片[1]-浅谈Minecraft Java版中的文本格式化-帆窝

大概就是这么个原理。在文本组件中,你可以定义文本的点击事件(鼠标左键点击)、悬停事件(鼠标悬停在文本上)和许多种文本格式,完整列表如下:

  • color:文本颜色
  • shadow_color:文本阴影颜色
  • font:文本字体
  • bold:粗体?
  • italic:斜体?
  • underlined:下划线?
  • strikethrough:删除线?
  • obfuscated:随机字符?(可以制作解密/恐怖地图里的掉san场景)
  • insertion:说是文本插入,没用过不知道
  • click_event:点击事件
  • hover_event:悬停事件

可以看出,文本组件实现了传统的格式代码的所有格式功能,同时增加了更多功能,同时易于编写和维护,也更加语义化。

那么,作为数据包作者,我们如何向玩家发送模样精美的文本呢?只需要在函数中编写tellraw命令,然后对玩家发送文本组件即可。命令中的文本组件需要写成SNBT格式,大概如下:

# 首先伪造一种清空聊天栏的错觉()
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}
tellraw @a {text: ""}

# 地图/数据包简介
tellraw @a { \
    text: "[ One Block Sky Island ]", \
    color: "green" \
}
tellraw @a { \
    text: "[ 单 方 块 空 岛 ]", \
    color: "green" \
}

tellraw @a { \
    text: "|—————————————————————————", \
    color: "yellow" \
}

tellraw @a { \
    text: "| 起源方块", \
    color: "yellow" \
}

tellraw @a { \
    text: "| | 坐标位于 0 63 0 的方块", \
    color: "yellow" \
}

tellraw @a { \
    text: "| | 无法被彻底破坏、可以无限获取资源", \
    color: "yellow" \
}

tellraw @a { \
    text: "| | 随游戏阶段前进,可获取的资源也会增加", \
    color: "yellow" \
}

tellraw @a { \
    text: "|—————————————————————————", \
    color: "yellow" \
}

tellraw @a { \
    text: "| 空岛阶段", \
    color: "yellow" \
}

tellraw @a { \
    text: "| | 随着起源方块被破坏总次数的增加", \
    color: "yellow" \
}

tellraw @a { \
    text: "| | 空岛将不断进入新的阶段", \
    color: "yellow" \
}

tellraw @a { \
    text: "| | 每个阶段都会带来新的方块与新的补给箱", \
    color: "yellow" \
}

tellraw @a { \
    text: "|—————————————————————————", \
    color: "yellow" \
}

# 游玩提示
tellraw @a {text: ""}

tellraw @a [ \
    {text: "首次游玩该存档? ", color: "green"}, \
    {text: "[ 开始游戏 ]", color: "gold", \
        hover_event: {action: "show_text", value: "这会导致已经开始的空岛进程被重置,别点错::>_<::"}, \
        click_event: {action: "run_command", command: "function oneblock:run/init_oneblock"} \
    } \
]
图片[2]-浅谈Minecraft Java版中的文本格式化-帆窝

同样,文本组件也可以被使用在游戏中的很多地方。对于此,芒果有一点小小的推论……

在模组中使用Text

Text是Minecraft中定义的文本接口,游戏中几乎所有的文本都是Text的延伸。Text拥有of方法可以直接从Java字符串创建Text对象,也拥有translate方法从翻译键获取本地化文本创建Text对象。

那么,上面提到的文本组件,在游戏内自然而然也会处理为Text对象,然后再给玩家在各个地方显示。但是在模组开发中,我们不满足于编写文本组件,而是想要直接创建带有格式、点击事件等的Text

我们就跳过繁琐的验证过程,直接展示在芒果的模组 GameHelper 的下个版本将要添加的代码片段:

Text.translatable("gamehelper.message.death_position_tp")
    .styled { style -> style
        .withColor(Colors.GREEN)
        .withUnderline(true)
        .withClickEvent(ClickEvent.RunCommand("/execute in ${payload.world} run tp ${payload.pos.x} ${payload.pos.y} ${payload.pos.z}"))
        .withHoverEvent(HoverEvent.ShowText(Text.translatable("gamehelper.screen.death_position.tp.description")))
    }

源码中的每个Text实例都带有一个Style实例,Style不出所料就是用来表示文本格式的类,包括点击事件和悬停事件也被包含在内了。Style是public的类,但是没有提供公开的构造方法,因此我们只能修改某个文本的样式而不能创建新的样式再把它给某个文本。

其实也不是不行……Style.EMPTY就可以获得新的白板样式了。不过,更符合直觉的方法还是获取Text自己的Style然后用with____这样的方法来修改样式。事实上,Minecraft解析文本组件的过程也正是根据文本组件中的样式创建一个Style然后扔给Text~

顺便一提

可能是对于文本颜色更改的需求明显比其他样式更多,Text拥有且仅拥有一个withColor方法可以直接修改文本颜色,其他的所有样式修改需求都必须显示获取Style然后做文章,这曾经一度让我以为模组能做的只有这么多了……自然不可能的啦~

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容