Files
netease-modsdk-wiki/docs/mcguide/28-电脑网络游戏/课程3:编写Bukkit插件/3-进阶内容/1-箱子GUI的实现.md
boybook 760c2dd9ad 2.6
2025-12-01 20:59:16 +08:00

110 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
front:
hard: 进阶
time: 20分钟
---
# Bukkit类与箱子GUI的实现
服务器里经常会利用箱子的GUI做“按钮菜单”功能. 有些服务器可能利用`ChestCommand`插件做出了各种花样的菜单.
如何写一个插件来实现这样的箱子GUI呢?
# Bukkit类
我们早在事件监听注册监听器时就已经见过`Bukkit`类了.
```java
Bukkit.getPluginManager().registerEvents(this,this);
```
`Bukkit`类是服务器的单例. 我们可以通过它操作服务器.
例如, 你可以用`Bukkit.banIP("某个IP")`来封禁某个IP号. 更多的用法可以在JavaDoc上查到.
你也可以利用`Server`对象操作服务器, 二者几乎没有差别(`Bukkit`类内部就是操作`Server`对象).
插件主类提供`getServer()`方法, 返回值就是一个`Server`对象.
# Inventory的使用
箱子GUI本质是一个Inventory界面. 首先我们需要创建一个Inventory对象出来.
但我们不必直接`new Inventory(...)`, 这是因为查阅JavaDocs可以得知Inventory是一个接口无法直接实例化。
但是`Bukkit`类给我们提供了创建`Inventory`对象的方法:
```java
Inventory inv = Bukkit.createInventory(player, 6*9, "URARA!");
//第一项是主人, 在这里可以设打开界面的玩家Player对象(还记得Inventory和箱子或玩家背包等一一对应吗)
//第二项必须是 9n (n是1≤n≤6的正整数)
//第三项是标题
ItemStack item_bk = new ItemStack(Material.DIAMOND);
//在四周设置钻石边框
//这里用这样脑残的写法是为了告诉你一个大概的意思
//我相信你实际写的时候不会这么简单粗暴解决问题的, 应该会用上循环解决, 对吧
inv.setItem(0,item_bk);
inv.setItem(1,item_bk);
inv.setItem(2,item_bk);
inv.setItem(3,item_bk);
inv.setItem(4,item_bk);
inv.setItem(5,item_bk);
inv.setItem(6,item_bk);
inv.setItem(7,item_bk);
inv.setItem(8,item_bk);
inv.setItem(9,item_bk);
inv.setItem(17,item_bk);
inv.setItem(18,item_bk);
inv.setItem(26,item_bk);
inv.setItem(27,item_bk);
inv.setItem(35,item_bk);
inv.setItem(36,item_bk);
inv.setItem(44,item_bk);
inv.setItem(45,item_bk);
inv.setItem(46,item_bk);
inv.setItem(47,item_bk);
inv.setItem(48,item_bk);
inv.setItem(49,item_bk);
inv.setItem(50,item_bk);
inv.setItem(51,item_bk);
inv.setItem(52,item_bk);
inv.setItem(53,item_bk);
ItemStack item_button1 = new ItemStack(Material.GOLD);
ItemStack item_button2 = new ItemStack(Material.ANVIL);
inv.setItem(22,item_button1);
inv.setItem(31,item_button2);
//然后可以给玩家打开这个Inventory(注意, 我们还没做限制, 这个时候玩家可以自由的在这个GUI里拿东西出来)
p.openInventory(inv);
```
然后我们监听`InventoryClickEvent`实现功能和限制:
```java
@EventHandler
public void onInventoryClick(InventoryClickEvent e){
//从这里可以看出来, 标题不是随意设置的, 我们经常用标题作为区分GUI的标志
if(e.getWhoClicked().getOpenInventory().getTitle().equals("URARA!")){
e.setCancelled(true); //这样玩家就没办法拿出来物品了
//getRawSlot获得玩家点击的格子编号
//但是玩家点击GUI之外不是格子的地方也会触发InventoryClickEvent, 需要做处理!
if(e.getRawSlot()<0 || e.getRawSlot()>e.getInventory().getSize() || e.getInventory()==null)
return;
//自从Mojang把HIM删掉以后, 能触发InventoryClickEvent的只有Player了
//目前来说可以直接把它强转成Player
Player p = (Player)e.getWhoClicked();
if(e.getRawSlot()==22){
p.sendMessage("你点击了金锭!");
p.closeInventory();
} else {
p.sendMessage("你没有点击金锭!");
p.closeInventory();
}
}
}
```
基于这个思路, 你可以做出一个有功能的箱子GUI了!
> 思考: 如果遇到了某些能够修改箱子GUI的标题的插件(比如帮助加前缀)
> 能不能利用 InventoryHolder 来区分GUI呢?