跳到主要内容

开发者 API

其他插件可以打开云界面画面、提供画面上的资料、处理按钮点击,以及随插件自动安装自己的画面。本系列插件(云公会、星月邮箱…)都是这样接上的。

取得 API​

plugin.yml 加上软依赖,编译时以 compileOnly 引入 CloudUI 的 jar:

softdepend: [CloudUI]
import dev.cloudplugins.ui.api.CloudUIApi;

CloudUIApi ui = Bukkit.getServicesManager().load(CloudUIApi.class); // 没装 CloudUI 时是 null

方法一览​

方法说明
boolean open(Player, String screen)打开画面;选单已经开着时切换过去。玩家不能使用画面时(见 usable)自动改用箱子选单。画面不存在、未授权、玩家死亡 / 旁观 / 坐载具 / 滑翔 / 睡觉时回传 false
void close(Player)、close(Player, Runnable)关闭选单;第二种在选单完全关闭后执行
boolean isOpen(Player)、String screen(Player)是否开着选单、目前的画面 ID
boolean usable(Player)这位玩家能不能看到云界面画面:基岩版、未授权、拒绝资源包、/cui classic 时是 false(这时可以改开自己的箱子 GUI,或照样 open 交给箱子备援)
void registerModel(Plugin, String screen, Function<Player, UiModel>)为某个画面提供资料,见 提供画面资料
void registerAction(Plugin, String name, Consumer<UiClick>)注册 custom: <name> 动作,见 注册动作
void unregisterActions(Plugin)移除这个插件注册的动作与资料(插件停用时)
void refresh(Player, boolean animate)资料变了时重新整理目前的画面
boolean notice(Player, String)在画面顶端显示通知横幅(MiniMessage);选单没开时回传 false,改用聊天或动作列
void describeKeys(Plugin, String screen, Map<String, String>)说明这个画面有哪些键名,网页编辑器会列出来
int installScreens(Plugin, String folder, Collection<String>)把插件 jar 里的画面与图片装进 CloudUI 文件夹,见 自动安装画面
void contribute(Plugin, String text, Collection<Integer> colors)预先把会用到的文字与颜色加进资源包(执行时才出现的固定文字)
Portrait portrait(Player)选单中角色的位置(feet()、yaw()、shown()),给要在角色身上显示东西的插件(例如时装)
boolean input(Player, String title, String body, Map<String,String> fields, int maxLength, Consumer<List<String>> done)在选单上弹出原版输入对话框,见 输入文字
void carry(Player, ItemStack)让游标「拿着」一个物品(拖放物品时显示),null 拿掉;只负责显示

提供画面资料​

画面里的 {键名} 先问你的 UiModel,回传 null 才轮到内建变量。每次打开画面时用 Function<Player, UiModel> 建一个新的 model。

public interface UiModel {
default String value(String key) { return null; } // {键名} 的值;格子里是 {grid.格号.键名}
default ItemStack item(String key) { return null; } // item: '{键名}' 的物品
default List<String> tooltip(String button) { return List.of(); } // 按钮的说明行
default boolean hover(String button) { return false; } // 游标移到按钮上;回传 true 会重新整理画面
default void click(UiClick click) { } // 没有注册处理器的 custom 动作
default void closed() { } // 画面关闭或切走
}

格子里的键名会自动加上格子 ID 与格号({name} → {rows.2.name}),在 value 里拆开判断即可。

注册动作​

按钮写 custom: claim,点击时呼叫:

ui.registerAction(this, "claim", click -> {
Player p = click.player();
// click.screen() 画面 ID
// click.button() 按钮 ID(格子里是 "rows.2.card")
// click.index() 格号(不在格子里是 -1);click.grid() 格子 ID
// click.right() 是不是右键
// click.value() custom: 后面写的内容
});

没有用 registerAction 注册的 custom 动作,会交给该画面 model 的 click(UiClick)。

自动安装画面​

把画面与图片放在插件 jar 的资源文件夹里(例如 cloudui/screens/myplugin.yml、cloudui/images/myplugin/bg.png),启动时安装:

ui.installScreens(this, "cloudui", List.of("screens/myplugin.yml", "images/myplugin/bg.png"));
  • 第三个参数是相对于 CloudUI 文件夹的路径,从 jar 的 <folder>/<路径> 复制过去。
  • 文件不存在就复制;之后插件更新时,服务器没改过的文件自动换成新版,改过的保留(记录在 installed.yml,控制台列出一次)。
  • 没有安装记录的旧文件(记录功能加入前安装的)会更新成新版,旧文件另存成同名的 .old。
  • 回传这次复制了几个文件。

输入文字​

在选单上弹出 Minecraft 原版的输入对话框(例如写信、取名):

Map<String, String> fields = new LinkedHashMap<>();
fields.put("收件人", "");
fields.put("标题", "");
boolean shown = ui.input(player, "写信", "填好后按确定", fields, 64, values -> {
if (values == null) return; // 按了取消(按 Esc 关掉不会呼叫)
String to = values.get(0), title = values.get(1);
});
if (!shown) {
// 弹不出对话框(例如玩家用箱子选单):改在聊天栏询问
}

最小范例​

screens/hello.yml:

elements:
greet:
type: text
text: '你好,{player}!今天签到了 {days} 天'
x: 960
y: 400
align: center
size: 40
sign:
type: button
image: common/button.png
x: 860
y: 500
click:
left: ['custom: hello-sign']

插件:

public final class HelloPlugin extends JavaPlugin {
@Override
public void onEnable() {
CloudUIApi ui = Bukkit.getServicesManager().load(CloudUIApi.class);
if (ui == null) return; // 没装 CloudUI
ui.installScreens(this, "cloudui", List.of("screens/hello.yml", "images/common/button.png"));
ui.registerModel(this, "hello", player -> new UiModel() {
@Override
public String value(String key) {
return key.equals("days") ? String.valueOf(signDays(player)) : null;
}
});
ui.describeKeys(this, "hello", Map.of("days", "连续签到天数"));
ui.registerAction(this, "hello-sign", click -> {
sign(click.player());
ui.notice(click.player(), "<green>签到成功");
ui.refresh(click.player(), false);
});
getCommand("hello").setExecutor((sender, cmd, label, args) -> {
if (sender instanceof Player p && !ui.open(p, "hello")) p.sendMessage("现在无法打开");
return true;
});
}

@Override
public void onDisable() {
CloudUIApi ui = Bukkit.getServicesManager().load(CloudUIApi.class);
if (ui != null) ui.unregisterActions(this);
}
}

第一次注册资料时,控制台会显示「已偵測到本系列插件 …,介面已啟用」。