外部插件需要编译依赖 Chorus-Bukkit-<version>.jar。
dependencies {
compileOnly(files("libs/Chorus-API-1.0.0-SNAPSHOT.jar"))
}
在 plugin.yml 中声明:
if (!ChorusAPI.isAvailable()) {
return;
}
ChorusService chorus = ChorusAPI.get();
API 只会在 Chorus 授权成功并完成业务启动后发布。依赖插件禁用时,应清理自己注册的扩展:
chorus.registerChannelProvider(this, 100, provider);
chorus.registerRecipientResolver(this, 100, resolver);
chorus.registerMessageProcessor(this, 100, processor);
chorus.registerFormatResolver(this, 100, resolver);
chorus.registerPlayerAction(this, 100, action);
priority 越大越先处理:
- 频道提供器按优先级合并,同 ID 保留最先出现的一项;
- 接收者解析器、格式解析器和玩家动作采用最先匹配的一项;
- 消息处理器会按优先级依次执行全部处理器。
这里的注册优先级只决定扩展处理顺序和同 ID 频道由哪个提供器持有。ChannelView.priority 才决定频道在聊天界面中的位置;所有提供器的频道合并去重后,会按该值从高到低排列。
这些回调由 Bukkit 主线程调用,不要直接执行阻塞数据库或网络请求。
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.bukkit.entity.Player;
import priv.seventeen.artist.chorus.api.ChannelProvider;
import priv.seventeen.artist.chorus.api.ChannelFormat;
import priv.seventeen.artist.chorus.api.ChannelScope;
import priv.seventeen.artist.chorus.api.ChannelView;
import priv.seventeen.artist.chorus.api.ChatMessage;
import priv.seventeen.artist.chorus.api.RecipientResolver;
ChannelView guild = new ChannelView(
"guild",
"公会",
500,
"chorus/icons/channel-guild.png",
"chorus/icons/channel-guild-light.png",
"§8[§d公会§8] §r",
"[公会] ",
true,
ChannelScope.GLOBAL,
"guild-members",
"guild.chat",
"guild.chat",
List.of(new ChannelFormat(
"default", 0, "", "§d{player}§8: §f{message}", 0
))
);
将频道交给 ChannelProvider,并为它的 recipientResolver 注册同名解析器。例如:
chorus.registerChannelProvider(this, 100, new ChannelProvider() {
@Override
public Collection<ChannelView> channels(Player viewer) {
return List.of(guild);
}
@Override
public Optional<ChannelView> find(String id) {
return guild.id().equals(id) ? Optional.of(guild) : Optional.empty();
}
});
chorus.registerRecipientResolver(this, 100, new RecipientResolver() {
@Override
public String id() {
return "guild-members";
}
@Override
public Collection<Player> resolveLocal(
ChatMessage message,
Collection<? extends Player> candidates
) {
return candidates.stream()
.filter(player -> guildService.sameGuild(message.sourceId(), player.getUniqueId()))
.toList();
}
});
示例中的 guildService 是附属插件自己的成员服务,跨服时每个子服都需要能读取正确的成员关系。
ChannelProvider.channels(viewer) 决定该玩家可见的频道列表,find(id) 用于发送和接收时查找频道。ChannelView.priority 数值越大,频道在 UI 中越靠前。RecipientResolver.resolveLocal() 收到已经过接收权限初筛的本服在线玩家,只应返回其中的子集。
这种方式已经完整提供频道,因此 channels.yml 不需要再出现 guild。如果希望由服主在 channels.yml 控制频道名称、图标、格式和排序,就不要注册 ChannelProvider,只注册配置中 recipient-resolver 对应的 RecipientResolver。
GLOBAL 频道不会自动同步外部插件的公会或队伍数据。每个 Bukkit 节点都要注册同名频道与解析器,并能读取一致的成员关系。
MessageProcessor 可以修改频道聊天、私聊或弹幕的正文,也可以拒绝消息。
chorus.registerMessageProcessor(this, 200, message -> {
if (message.body().contains("forbidden")) {
return ProcessResult.reject(message, "§c这条消息不能发送");
}
return ProcessResult.allow(message.withBody(message.body().trim()));
});
拒绝说明会通过 Chorus 短提示显示给发送者。处理器不应修改消息 ID、来源和目标来绕过路由规则。
FormatResolver 可根据玩家和频道返回自定义 ResolvedFormat。普通频道的 fontSize 可以为 0,弹幕格式必须在 12..72 之间。如果外部解析器都未返回结果,Chorus 的内置解析器会按频道格式的 priority 选择玩家有权限使用的第一种;每个频道仍须提供无权限要求的默认格式。
player-actions.yml 负责按钮外观和触发方式,API 的 PlayerAction 负责 ACTION 类型的实际业务:
chorus.registerPlayerAction(this, 100, new PlayerAction() {
@Override
public String id() {
return "party-invite";
}
@Override
public Optional<PlayerActionInput> input() {
return Optional.empty();
}
@Override
public void execute(PlayerActionContext context) {
partyService.invite(context.viewer(), context.targetId());
}
});
每个 PlayerAction 都需要实现 input();不需要输入时返回 Optional.empty()。需要一行额外输入时,可返回 PlayerActionInput:标签最多 32 字符,占位文字最多 128 字符,最大输入长度范围为 1..4096。占位文字可使用 {target},由服务端替换成目标玩家名。目标 UUID 来自服务端保存的点击上下文,不由客户端提交。对应按钮仍需在 player-actions.yml 中配置 ACTION 触发器,trigger.value 应与 id() 相同。
| 方法 | 用途 |
|---|
selectChannel(player, channelId) | 为玩家选择频道并同步界面 |
openPlayerActions(viewer, targetId) | 打开目标玩家的操作菜单 |
sendPrivate(sender, targetId, message) | 发送经过长度、Redact、屏蔽和代理路由的私聊 |
sendRaw(target, message) | 向当前节点玩家发送不经过频道格式的颜色文本 |
sendCard(target, cardId, data) | 向当前节点玩家发送已注册卡片 |
showNotice(target, message, tone) | 在常驻聊天 HUD 显示短提示 |
NoticeTone 支持 INFO、SUCCESS、WARNING 和 ERROR。短提示不会受当前聊天频道的前缀过滤影响,适合显示队伍频道无人接收、操作失败等业务反馈。