Skip to content

Latest commit

 

History

History
228 lines (151 loc) · 7.97 KB

5-6.md

File metadata and controls

228 lines (151 loc) · 7.97 KB

5-6 原始 JSON 文本

在 Minecraft 原版中,我们可以为文字定义一些特殊效果,例如鼠标移上去时显示介绍,单击复制到剪贴板……这不是什么魔法,事实上,实现这样的功能很简单。

这项功能叫原始 JSON 文本,如果不知道它,可以先阅读 Wiki 上的有关内容

在 Bukkit 中,我们无法直接发送一个 JSON 对象到客户端,但这不算什么,有人已经为我们提供了等效的 API。

BungeeCord 提供的 API

这一套 API 不是 Bukkit API 的一部分,它是由 BungeeCord 提供的。哦,别紧张,我们不需要额外的库。由于这个 API 很常用,它已经被 Spigot 和 Paper 等服务端集成了。

BungeeCord 的聊天 API 位于 net.md_5.bungee.chat 这个包下,看到 md_5 时你是不是「咯噔」了一下?没错,笔者一开始也想到了 4-1 时候的噩梦,不过后来发现,这是误会。md_5 是 Spigot 服务端的一位作者——BungeeCord 是 TA 开发的。

要说明的是,BungeeCord 的 JavaDocs 并不是 Paper 的一部分,它有自己的 JavaDocs:

https://javadoc.io/static/net.md-5/bungeecord-chat/1.16-R0.4/net/md_5/bungee/api/chat/package-summary.html

另外,这里我们只是要实现聊天栏按钮这一功能,因此仅介绍此 API 的一部分。

演示

BungeeCord 就 BungeeCord 吧,反正能够实现我们的功能就行。

我们要用到的是 net.md_5.bungee.chat.TextComponent 这个类。

下面我们演示如何创建一个链接,并且在玩家单击时让 Minecraft 将其打开。

BaseComponent url = new TextComponent("点我前往 Love-And-Tolerance 官网!");
// 创建一个文本组件
url.setHoverEvent(new HoverEvent(
    HoverEvent.Action.SHOW_TEXT, // 动作:显示文本
    new Text("https://love-tolerance.com/") // 内容:普通文本
));
url.setClickEvent(new ClickEvent(
    ClickEvent.Action.OPEN_URL, // 动作:打开 URL
    "https://love-tolerance.com/" // 要打开的 URL
));
url.setColor(ChatColor.GOLD);
// 设置颜色
Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG")).sendMessage(url);
// 发送!

我们先不谈它是什么原理,我们看看效果(1.16.5 原版,资源包是 Love-And-Tolerance,语言是 Modern Equish Full):

SHOW

AHA

好,接下来我们解释这是怎么做到的。

分块

首先,我们要转换一下思路,在 BungeeCord 开发者的眼里,一个文本可以被拆分成不可再分的小「块」,这个「块」就是 BaseComponent,它是下面要说到的 TextComponent 的父类。

每一「块」具有这样的特点:

  • 同样的颜色和样式(加粗、斜体等)
  • 同样的行为(悬浮标签和点击操作等)

上面的例子中,整个 URL 是一「块」,因为它样式相同(金色),行为相同(悬浮显示 URL,点击打开 URL)。

分块之后,我们只需要分别创建每一块就可以了。

基础文本

首先,实例化一个 TextComponent

BaseComponent url = new TextComponent("基本文本");

这里的文本是基本文本,稍后将对它们整体设置样式。

那我要是想分别设置每一个字的样式呢?

对不起,不行,这是一「块」,样式应当相同。如果需要单独设置样式,请将它接着拆分。

然后我们可以对其设置颜色与样式:

url.setColor(ChatColor.GOLD); // 颜色
url.setBold(true); // 加粗
url.setItalic(true); // 斜体
url.setUnderlined(true); // 下划线
url.setStrikeThrough(true); // 删除线
url.setObfuscated(true); // 变模糊

请留意一下,这里的 ChatColornet.md_5.bungee.api.ChatColor,不是 org.bukkit.ChatColor

接下来进入最有趣的部分。

设置鼠标悬浮事件

setHoverEvent 设置当鼠标悬浮时要做的事。

这个方法需要一个 HoverEvent 对象,该对象的构造方法如下:

public HoverEvent(
    HoverEvent.Action action,
    Content content
)

action 表示「要做之事」,content 表示显示的内容。

说到「要做之事」,你可能会想到事件处理,很遗憾,这里不行,事实上 Minecraft 能做的事情很有限,那都有哪些事情呢?参考 HoverEvent.Action 枚举,我们看到:

public static enum Action {
        SHOW_TEXT, // 显示文本
        SHOW_ITEM, // 显示物品
        SHOW_ENTITY; // 显示实体标签
}

实际上 content 的类型是与 action 有关的:,不能随便写:

  • 如果 actionSHOW_TEXTcontent 就得是 new Text(...)
  • 如果 actionSHOW_ITEMcontent 就得是 new Item(...)
  • 如果 actionSHOW_ENTITYcontent 就得是 new Entity(...)

TextItemEntity 都是 net.md_5.bungee.api.chat.hover.content 包下的,别导入错了!

我们逐一介绍。

Text 类的构造方法很简单:

public Text(String text)

提供一个 String 即可。

Item 用于基于 NBT 显示物品的信息,至于怎么获取 NBT……自己看着办吧(笑)。

public Item(
    String id,
    int count, 
    ItemTag tag
) // Item 构造方法

ItemTag tag = ItemTag.ofNbt(<NBT 标签>.toString());
// 如何制造 ItemTag,NBT 的获取可以使用反射

Entity 类用于显示一个实体的信息:

public Entity(
    String type, // 类型,尚不明确
    @NonNull String id, // getUniqueId().toString() 即可
    BaseComponent name // 名字,也可以使用 BaseComponent,例如 new TextComponent("SHEEP_REALMS")
)

提供的 UUID 可能是与某个实体相关的……也不明确。

总而言之,虽然鼠标悬浮时可以显示文本、物品、实体,但只有文本才用起来方便

设置点击事件

setClickEvent 设置当点击时要做的事。

这个方法需要一个 ClickEvent 对象,该对象的构造方法如下:

public ClickEvent(
    ClickEvent.Action action,
    String content
)

和上面很像,只不过 content 变成了普通的 String

点击时能做的事同样很有限,可以参考 ClickEvent.Action

OPEN_URL, // 建议打开 URL
OPEN_FILE, // 打开文件,多人游戏无法使用
RUN_COMMAND, // 以玩家身份运行命令
SUGGEST_COMMAND, // 建议玩家使用命令
CHANGE_PAGE, // 换页,仅在书中可用
COPY_TO_CLIPBOARD; // 复制到剪贴板

OPEN_FILE 多人游戏中无法使用,因此不介绍。

OPEN_URL 用于建议客户端打开一个 URL,content 即为 URL 地址。

RUN_COMMAND 以玩家身份执行 content(需要带 /),这是聊天栏按钮最大的作用,你可以控制玩家执行一条命令,并使用命令处理器完成处理,这也是一种 CLI。

SUGGEST_COMMANDcontent 打在玩家聊天窗口,但不默认发送,需要玩家确认。

COPY_TO_CLIPBOARD 单击将 content 复制到剪贴板。

CHANGE_PAGE 用于切换书页,仅用在 BookMetasetPages 方法中。虽然页面是 int 类型,但这里还是要写成 String

new ClickEvent(ClickEvent.Action.CHANGE_PAGE, "3");
// 切换第三页

用这个方法做出每一「块」后,再将它们小心地收集到一起,以后就可以使用它们啦!

发送消息,设置书页,设置告示牌时都可以使用呢……而且这些方法通常都支持多个 BaseComponent,依次填进去就行啦。


因此我们总结出使用奇特文本的方法:

  1. 创建 TextComponent
  2. 设置样式
  3. 设置悬浮事件:
    • new HoverEvent(HoverEvent.Action.XXX, new XXX(...))
  4. 设置点击事件:
    • new ClickEvent(ClickEvent.Action.XXX, "参数")
  5. 放到需要的地方去

就这些,很简单,对吧?配合命令使用,TextComponent 能够发挥出不小的威力呢~