MenuBackpack.java v1.0
在玩家生存模式背包内定义"菜单格",配置物品lore和点击执行命令,支持自定义配置与reload命令
命令列表
- menuinvreload重载菜单背包配置
package com.menu.backpack;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.io.IOException;
import java.util.*;
import org.bukkit.configuration.file.YamlConfiguration;
/**
* @pluginName MenuBackpack
* @author ScriptIrc
* @version 1.0
* @description 在玩家生存模式背包内定义"菜单格",配置物品lore和点击执行命令,支持自定义配置与reload命令
* [command]menuinvreload|重载菜单背包配置[/command]
* [Permission]menuinv.reload|允许重载插件配置[/Permission]
*/
public class MenuBackpackPlugin extends JavaPlugin implements Listener {
// 配置文件对象
private YamlConfiguration config;
// 菜单格子配置:格编号->MenuSlot信息
private Map<Integer, MenuSlot> menuSlots = new HashMap<>();
// 菜单格自定义结构体
public static class MenuSlot {
public Material material;
public String displayName;
public List<String> lore;
public String command;
public MenuSlot(Material m, String name, List<String> lore, String cmd) {
this.material = m;
this.displayName = name;
this.lore = lore;
this.command = cmd;
}
}
@Override
public void onEnable() {
getLogger().info("MenuBackpack插件正在启用...");
saveDefaultConfigFile();
reloadMenuConfig();
Bukkit.getPluginManager().registerEvents(this, this);
getLogger().info("已注册事件监听器和菜单配置加载完成!");
}
@Override
public void onDisable() {
getLogger().info("MenuBackpack插件已关闭。");
}
/**
* 保存默认配置文件,如果不存在则生成并写入样板
*/
private void saveDefaultConfigFile() {
File file = new File(getDataFolder(), "menu_backpack.yml");
if (!file.exists()) {
try {
getDataFolder().mkdirs();
file.createNewFile();
// 写入配置样板,方便用户修改
YamlConfiguration yc = new YamlConfiguration();
// 格子编号如0为第一格,8为第一排第9格
Map<String, Object> slot0 = new HashMap<>();
slot0.put("material", "DIAMOND");
slot0.put("display", "§b钻石菜单按钮");
slot0.put("lore", Arrays.asList("§7点击执行命令", "§a/say Hello!"));
slot0.put("command", "say §e你点击了钻石菜单!");
yc.set("slots.0", slot0);
yc.set("slots.8.material", "GOLD_INGOT");
yc.set("slots.8.display", "§6黄金按钮");
yc.set("slots.8.lore", Arrays.asList("§e点我获得金币", "§a/give <player> gold_ingot 1"));
yc.set("slots.8.command", "give %player% gold_ingot 1");
yc.save(file);
} catch (IOException e) {
getLogger().warning("默认配置文件生成失败!");
}
}
}
/**
* 重载菜单配置,供reload命令和onEnable使用
*/
private void reloadMenuConfig() {
File file = new File(getDataFolder(), "menu_backpack.yml");
config = YamlConfiguration.loadConfiguration(file);
menuSlots.clear();
// slots可指定多个格
if (config.isConfigurationSection("slots")) {
Set<String> keys = config.getConfigurationSection("slots").getKeys(false);
for (String key : keys) {
try {
int slot = Integer.parseInt(key); // 背包格编号 0~35 (玩家主背包36格)
Material material = Material.matchMaterial(config.getString("slots." + key + ".material", "STONE"));
String display = config.getString("slots." + key + ".display", "§f菜单按钮");
List<String> lore = config.getStringList("slots." + key + ".lore");
String command = config.getString("slots." + key + ".command", "say %player% 点击了菜单!");
if (material != null) {
menuSlots.put(slot, new MenuSlot(material, display, lore, command));
}
} catch (Exception e) {
getLogger().warning("读取菜单格配置失败: " + key);
}
}
getLogger().info("已加载菜单格配置: "+menuSlots.size()+" 个格子");
} else {
getLogger().warning("未找到菜单格配置,请检查 menu_backpack.yml!");
}
}
/**
* 实现命令/menuinvreload 用于管理员手动重载配置
*/
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if ("menuinvreload".equalsIgnoreCase(label)) {
if (sender.hasPermission("menuinv.reload")) {
reloadMenuConfig();
sender.sendMessage("§a菜单背包配置已重载!");
} else {
sender.sendMessage("§c你没有重载权限!");
}
return true;
}
return false;
}
/**
* 玩家打开背包事件,为其指定菜单格自动填充菜单物品
*/
@EventHandler
public void onInventoryOpen(InventoryOpenEvent event) {
// 只处理主背包界面
if (!(event.getPlayer() instanceof Player)) return;
if (event.getInventory().getType() != InventoryType.PLAYER) return;
Player player = (Player) event.getPlayer();
Inventory inv = player.getInventory();
for (Map.Entry<Integer, MenuSlot> entry : menuSlots.entrySet()) {
int slot = entry.getKey();
MenuSlot ms = entry.getValue();
ItemStack is = new ItemStack(ms.material);
ItemMeta meta = is.getItemMeta();
if (meta != null) {
meta.setDisplayName(ms.displayName);
meta.setLore(ms.lore);
is.setItemMeta(meta);
}
inv.setItem(slot, is); // 填充菜单格
}
}
/**
* 玩家背包点击事件,判断点击格并处理
*/
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player)) return;
Inventory inv = event.getInventory();
// 只处理玩家背包
if (inv.getType() != InventoryType.PLAYER) return;
int slot = event.getRawSlot();
if (menuSlots.containsKey(slot)) {
event.setCancelled(true); // 阻止菜单格物品被拖动或替换
MenuSlot ms = menuSlots.get(slot);
Player player = (Player) event.getWhoClicked();
// 执行菜单格命令,支持%player%变量替换为玩家名
String cmd = ms.command.replace("%player%", player.getName());
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
player.sendMessage("§a你点击了菜单按钮!");
}
}
/**
* 玩家加入时同步菜单物品以防以奇异Bug丢失
*/
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
Inventory inv = player.getInventory();
Bukkit.getScheduler().runTaskLater(this, () -> {
for (Map.Entry<Integer, MenuSlot> entry : menuSlots.entrySet()) {
int slot = entry.getKey();
MenuSlot ms = entry.getValue();
ItemStack is = new ItemStack(ms.material);
ItemMeta meta = is.getItemMeta();
if (meta != null) {
meta.setDisplayName(ms.displayName);
meta.setLore(ms.lore);
is.setItemMeta(meta);
}
inv.setItem(slot, is);
}
}, 20L); // 延迟1秒执行以保证同步
}
}