huanmeng_cn
本帖最后由 huanmeng_cn 于 2023-3-19 21:32 编辑

本教程与源码可能存在Kotlin编程语言,请谨慎阅读。
阅读及代表你已具有基本的Java&Kotlin&Bukkit/Gui的开发基础。

完整代码: https://github.com/huanmeng-qwq/Gui/

一、结构

AbstractGui作为最基础的Gui封装类,GuiCustom则对应自定义Gui最通用的封装也是对AbstractGui的实现。GuiPage则是继承自GuiCustom,可以实现翻页功能。

二、如何使用首先初始化GuiManager,只需一行即可。

GuiManager只能初始化一次,如果重复初始化将抛出异常IllegalArgumentException
  1. public class ExamplePlugin extends JavaPlugin {
  2.     @Override
  3.     public void onEnable() {
  4.         new GuiManager(this);
  5.     }
  6. }
复制代码

、自定义Gui首先参加一个基本的Gui
  1. GuiCustom gui = new GuiCustom(player);
  2. // Gui行数为3行
  3. gui.line(3);
  4. // Gui标题
  5. gui.title("Test Gui");
复制代码
然后开始设置按钮以及操作:1. 比如点击获取泥土(是不是太土了
  1. gui.draw().set(Slot.of(0), /*图标*/Button.of(p -> {
  2.     return new ItemBuilder(Material.DIRT).setName("§b点击获取泥土").build();
  3. }, /*点击时触发*/p -> {
  4.     p.getInventory().addItem(new ItemStack(Material.DIRT));
  5. }));
复制代码
2. 或者是左键获得泥土,右键获得火把
  1. gui.draw().set(Slot.of(1), /*图标*/Button.of(p -> {
  2.     return new ItemBuilder(Material.DIRT).setName("§b左击获取泥土").addLore("§e右键获取火把").build();
  3. },/*点击时触发*/ (p, click, action, slotType, slot, hotBarKey) -> {
  4.     if (click.isLeftClick()) {
  5.         p.getInventory().addItem(new ItemStack(Material.DIRT));
  6.     } else {
  7.         p.getInventory().addItem(new ItemStack(Material.TORCH));
  8.     }
  9. }));
复制代码
3. 也可以随机获得一个物品
  1. Random random = new Random();
  2. List<Material> list = Arrays.asList(Material.DIRT, Material.APPLE, Material.DIAMOND, Material.EMERALD);
  3. gui.draw().set(Slot.of(2), new Button() {
  4.     private ItemStack itemStack;
  5.     @Override
  6.     public ItemStack getShowItem(Player player) {
  7.         Material randomEle = list.get(random.nextInt(list.size()));
  8.         return itemStack = new ItemBuilder(randomEle).setName("§a点击随机获取物品").build();
  9.     }
  10.     @Override
  11.     public Result onClick(Slot slot, Player player, ClickType click, InventoryAction action, InventoryType.SlotType slotType, int slotKey, int hotBarKey, InventoryClickEvent e) {
  12.         player.getInventory().addItem(itemStack);
复制代码
4. 上点难度,根据图案绘制
  1. gui.draw().set(
  2.         Slots.pattern(new String[]{
  3.                 "---------",
  4.                 "-xxxxxxx-",
  5.                 "---------"
  6.         }, 'x'),
  7.         /*这里也可以传List<Button> 每个element将对应每个x所在位置*/
  8.         Button.of(
复制代码

5. 其它案例 可以去看看ItemStackEditor编写的物品编辑器

四、翻页Gui


首先构建好所有按钮放入一个List<Button>,可以这样:
  1. List<Button> buttons = new ArrayList<>();
  2. for (int i = 0; i < 100; i++) {
  3.     buttons.add(Button.of(p -> new ItemBuilder(Material.DIRT).setName("§b点击获取泥土").build(), p -> p.getInventory().addItem(new ItemStack(Material.DIRT))));
  4. }
复制代码
然后构建一个GuiPage18是每页18个元素
  1. GuiPage gui = new GuiPage(player, buttons, 18, Slots.PATTERN_LINE_DEFAULT);
复制代码
接下来设置一下刷新
  1. gui.tick(10);
  2. gui.addTick(g -> g.refresh(true));
复制代码
最后添加一下下一页上一页的按钮
  1. gui.addAttachedButton(
  2.         new GuiButton(
  3.                 Slot.ofGame(1, 4),
  4.                 Button.of(
  5.                         p -> {
  6.                             if (gui.pagination().hasLast(gui.page())) {
  7.                                 return new ItemBuilder(Material.ARROW, "§a下一页").build();
  8.                             } else {
  9.                                 return new ItemStack(Material.AIR);
  10.                             }
  11.                         },
  12.                         /*点击后刷新所有按钮*/
  13.                         (PlayerClickCancelUpdateAllInterface) (p, click, action, slotType, slot, hotBarKey) -> {
  14.                             if (gui.pagination().hasLast(gui.page())) {
  15.                                 gui.page(gui.page() - 1);
  16.                             }
  17.                         }
  18.                 )
  19.         )
  20. );
  21. gui.addAttachedButton(
  22.         new GuiButton(
  23.                 Slot.ofGame(9, 4),
  24.                 Button.of(
  25.                         p -> {
  26.                             if (gui.pagination().hasNext(gui.page())) {
  27.                                 return new ItemBuilder(Material.ARROW, "§a下一页").build();
  28.                             } else {
  29.                                 return new ItemStack(Material.AIR);
  30.                             }
  31.                         },
  32.                         /*点击后刷新所有按钮*/
  33.                         (PlayerClickCancelUpdateAllInterface) (p, click, action, slotType, slot, hotBarKey) -> {
  34.                             if (gui.pagination().hasNext(gui.page())) {
  35.                                 gui.page(gui.page() + 1);
  36.                             }
  37.                         }
  38.                 )
  39.         )
  40. );
复制代码
最后你就可以open()了!
五、maven:
已发布到Maven中心仓库
  1. <dependency>
  2.     <groupId>com.huanmeng-qwq</groupId>
  3.     <artifactId>Bukkit-Gui</artifactId>
  4.     <version>1.2</version>
  5. </dependency>
复制代码

对于Spigot1.16.5+的开发者
  1. <dependency>
  2.     <groupId>com.huanmeng-qwq</groupId>
  3.     <artifactId>Bukkit-Gui</artifactId>
  4.     <version>1.2</version>
复制代码
并在plugin.yml中添加:
  1. libraries:
  2.    - com.huanmeng-qwq:Bukkit-Gui:1.2
复制代码




teddyxlandlee
我去,这玩意太赞了
老哥不妨给仓库打个License(?)
话说你的依赖是kotlin写的,我是否需要安装taboolib之类的前置呢?

结冰的离季
你好,我只是粗略的看了一下 GuiManager,因为我踩过一些坑,您似乎没有考虑以下几种情况
1. 打开物品栏对着物品按F, 您有检查0~9但是F似乎没有,在某些版本中可以卡下来
2. 双击非菜单格子的同类物品,比如菜单有个 白板石头,物品栏也有,这时双击物品栏可以把相同的物品收集到鼠标上
3. Shift点击背包里的物品可能可以放到菜单的空格里
...
我觉得作为菜单库应该尽可能减少不必要的判断,比如以上的情况可以通过InventoryClickEvent判断出来,
按钮应该专注于响应点击而不是判断点击是否合法,所以GuiManager是有必要考虑以上情况的

如果您已经考虑了以上的情况请无视本消息

huanmeng_cn
teddyxlandlee 发表于 2023-3-17 19:53
我去,这玩意太赞了
老哥不妨给仓库打个License(?)
话说你的依赖是kotlin写的,我是否需要安装taboolib ...

感谢,已添加License。
不需要再额外安装Taboolib,这个本身也不是一个插件,仅仅作为一个开发者的依赖库的这种性质

huanmeng_cn
结冰的离季 发表于 2023-3-17 20:06
你好,我只是粗略的看了一下 GuiManager,因为我踩过一些坑,您似乎没有考虑以下几种情况
1. 打开物品栏对 ...

我在1.12.2版本试着测试了一下按F并没有反应,可以的话方便提供一下版本吗
双击非菜单格子的同类物品,如果点击按钮没用特意返回Result.ALLOW值的话是不会存在这种问题的
Shift点击背包里的物品移到上方Gui这个问题,默认点击背包物品是会被cancel掉的(cancelClickBottom),而且不符合clickInventory==inventory的条件

是的,一般来说每个按钮都应该只考虑响应的逻辑,所以Button接口提供了很多静态方法来快速的实现这些一个功能,当然也有支持复杂的处理点击判断的支持

结冰的离季
huanmeng_cn 发表于 2023-3-17 20:38
我在1.12.2版本试着测试了一下按F并没有反应,可以的话方便提供一下版本吗
双击非菜单格子的同类物品,如 ...

1.19吧,反正各种情况多试试总没错
默认取消点击岂不是玩家不能在菜单打开的状态下移动自己的库存了

huanmeng_cn
本帖最后由 huanmeng_cn 于 2023-3-18 01:02 编辑
结冰的离季 发表于 2023-3-17 20:42
1.19吧,反正各种情况多试试总没错
默认取消点击岂不是玩家不能在菜单打开的状态下移动自己的库存了 ...

感谢,1.19测试确实存在这个问题,但是放到副手中的物品是虚拟的,是无法使用的,目前1.2版本已对这个问题做出优化
默认取消点背包也可以手动关闭掉: gui.setCancelClickBottom(false);