ExpShopMenu.java v1.0
基于玩家经验点数的四分类分页商店菜单,左键出售右键收购,农作物/方块/工具/防具四页,支持经验点交易。
命令列表
- shopmenu打开经验点商店菜单
package com.scriptirc.shopmenu;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
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.util.*;
/**
* @pluginName ExpShopMenu
* @author Scriptirc
* @version 1.0
* @description 基于玩家经验点数的四分类分页商店菜单,左键出售右键收购,农作物/方块/工具/防具四页,支持经验点交易。
* [command]shopmenu|打开经验点商店菜单[/command]
* [Permission]expshopmenu.use|允许玩家使用经验点商店菜单[/Permission]
*/
public class ExpShopMenu extends JavaPlugin implements Listener {
private enum ShopCategory {
CROPS, BLOCKS, TOOLS, ARMOR
}
private static class ShopItem {
public final Material material;
public final String name;
public final int buyExp;
public final int sellExp;
public final int amount;
public ShopItem(Material material, String name, int buyExp, int sellExp, int amount) {
this.material = material;
this.name = name;
this.buyExp = buyExp;
this.sellExp = sellExp;
this.amount = amount;
}
}
private static final Map<ShopCategory, List<ShopItem>> SHOP_ITEMS = new HashMap<>();
private static final int ITEMS_PER_PAGE = 21;
private static final Map<ShopCategory, String> CATEGORY_TITLES = new HashMap<>();
static {
SHOP_ITEMS.put(ShopCategory.CROPS, Arrays.asList(
new ShopItem(Material.WHEAT, "小麦", 8, 4, 16),
new ShopItem(Material.CARROT, "胡萝卜", 8, 4, 16),
new ShopItem(Material.POTATO, "马铃薯", 8, 4, 16),
new ShopItem(Material.BEETROOT, "甜菜根", 10, 5, 16),
new ShopItem(Material.MELON_SLICE, "西瓜片", 6, 3, 16),
new ShopItem(Material.PUMPKIN, "南瓜", 12, 6, 8),
new ShopItem(Material.SUGAR_CANE, "甘蔗", 7, 3, 16),
new ShopItem(Material.BAMBOO, "竹子", 5, 2, 16)
));
SHOP_ITEMS.put(ShopCategory.BLOCKS, Arrays.asList(
new ShopItem(Material.STONE, "石头", 10, 5, 32),
new ShopItem(Material.COBBLESTONE, "圆石", 8, 4, 32),
new ShopItem(Material.OAK_LOG, "橡木原木", 16, 8, 16),
new ShopItem(Material.SAND, "沙子", 8, 4, 32),
new ShopItem(Material.DIRT, "泥土", 6, 3, 32),
new ShopItem(Material.GLASS, "玻璃", 12, 6, 16),
new ShopItem(Material.BRICKS, "砖块", 20, 10, 8)
));
SHOP_ITEMS.put(ShopCategory.TOOLS, Arrays.asList(
new ShopItem(Material.IRON_PICKAXE, "铁镐", 80, 40, 1),
new ShopItem(Material.IRON_AXE, "铁斧", 80, 40, 1),
new ShopItem(Material.IRON_SHOVEL, "铁锹", 60, 30, 1),
new ShopItem(Material.DIAMOND_PICKAXE, "钻石镐", 320, 160, 1),
new ShopItem(Material.DIAMOND_AXE, "钻石斧", 320, 160, 1),
new ShopItem(Material.DIAMOND_SHOVEL, "钻石锹", 240, 120, 1)
));
SHOP_ITEMS.put(ShopCategory.ARMOR, Arrays.asList(
new ShopItem(Material.IRON_HELMET, "铁头盔", 70, 35, 1),
new ShopItem(Material.IRON_CHESTPLATE, "铁胸甲", 120, 60, 1),
new ShopItem(Material.IRON_LEGGINGS, "铁护腿", 100, 50, 1),
new ShopItem(Material.IRON_BOOTS, "铁靴子", 70, 35, 1),
new ShopItem(Material.DIAMOND_HELMET, "钻石头盔", 280, 140, 1),
new ShopItem(Material.DIAMOND_CHESTPLATE, "钻石胸甲", 480, 240, 1),
new ShopItem(Material.DIAMOND_LEGGINGS, "钻石护腿", 400, 200, 1),
new ShopItem(Material.DIAMOND_BOOTS, "钻石靴子", 280, 140, 1)
));
CATEGORY_TITLES.put(ShopCategory.CROPS, "§a农作物商店");
CATEGORY_TITLES.put(ShopCategory.BLOCKS, "§e方块商店");
CATEGORY_TITLES.put(ShopCategory.TOOLS, "§b工具商店");
CATEGORY_TITLES.put(ShopCategory.ARMOR, "§d防具商店");
}
private final Map<UUID, MenuSession> menuSessionMap = new HashMap<>();
@Override
public void onEnable() {
Bukkit.getPluginManager().registerEvents(this, this);
getLogger().info("经验点商店菜单插件已启用!");
}
@Override
public void onDisable() {
menuSessionMap.clear();
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("§c只有玩家才能使用商店菜单!");
return true;
}
Player player = (Player) sender;
if (!player.hasPermission("expshopmenu.use")) {
player.sendMessage("§c你没有权限使用经验点商店菜单!");
return true;
}
openMainMenu(player);
return true;
}
private void openMainMenu(Player player) {
Inventory inv = Bukkit.createInventory(null, 27, "§6经验点商店 §7- 分类选择");
inv.setItem(10, createMenuItem(Material.WHEAT, "§a农作物商店", Arrays.asList("§7出售/收购农作物", "§e点击进入")));
inv.setItem(12, createMenuItem(Material.STONE, "§e方块商店", Arrays.asList("§7出售/收购方块", "§e点击进入")));
inv.setItem(14, createMenuItem(Material.IRON_PICKAXE, "§b工具商店", Arrays.asList("§7出售/收购工具", "§e点击进入")));
inv.setItem(16, createMenuItem(Material.IRON_CHESTPLATE, "§d防具商店", Arrays.asList("§7出售/收购防具", "§e点击进入")));
player.openInventory(inv);
menuSessionMap.put(player.getUniqueId(), new MenuSession(null, 0));
}
private void openShopMenu(Player player, ShopCategory category, int page) {
List<ShopItem> items = SHOP_ITEMS.get(category);
int totalPages = (items.size() - 1) / ITEMS_PER_PAGE + 1;
int start = page * ITEMS_PER_PAGE;
int end = Math.min(start + ITEMS_PER_PAGE, items.size());
Inventory inv = Bukkit.createInventory(null, 27, CATEGORY_TITLES.get(category) + " §7- 第" + (page + 1) + "/" + totalPages + "页");
for (int i = start; i < end; i++) {
ShopItem si = items.get(i);
List<String> lore = new ArrayList<>();
lore.add("§a左键§7出售: §e+" + si.sellExp + "§7经验点/" + si.amount + "件");
lore.add("§b右键§7收购: §e-" + si.buyExp + "§7经验点/" + si.amount + "件");
lore.add("§8点击交易");
inv.setItem(9 + (i - start), createMenuItem(si.material, "§f" + si.name, lore));
}
if (page > 0)
inv.setItem(21, createMenuItem(Material.ARROW, "§a上一页", Arrays.asList("§7点击返回上一页")));
if (page < totalPages - 1)
inv.setItem(23, createMenuItem(Material.ARROW, "§a下一页", Arrays.asList("§7点击前往下一页")));
inv.setItem(26, createMenuItem(Material.BARRIER, "§c返回主菜单", Arrays.asList("§7点击返回分类选择")));
player.openInventory(inv);
menuSessionMap.put(player.getUniqueId(), new MenuSession(category, page));
}
private ItemStack createMenuItem(Material mat, String name, List<String> lore) {
ItemStack item = new ItemStack(mat);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(name);
if (lore != null) meta.setLore(lore);
item.setItemMeta(meta);
return item;
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player)) return;
Player player = (Player) event.getWhoClicked();
String title = event.getView().getTitle(); // 修正为通过 InventoryView 获取标题
if (title == null) return;
if (title.contains("经验点商店") && title.contains("分类选择")) {
event.setCancelled(true);
ItemStack clicked = event.getCurrentItem();
if (clicked == null || clicked.getType() == Material.AIR) return;
switch (clicked.getType()) {
case WHEAT:
openShopMenu(player, ShopCategory.CROPS, 0); break;
case STONE:
openShopMenu(player, ShopCategory.BLOCKS, 0); break;
case IRON_PICKAXE:
openShopMenu(player, ShopCategory.TOOLS, 0); break;
case IRON_CHESTPLATE:
openShopMenu(player, ShopCategory.ARMOR, 0); break;
default: break;
}
return;
}
for (ShopCategory cat : ShopCategory.values()) {
if (title.contains(CATEGORY_TITLES.get(cat))) {
event.setCancelled(true);
ItemStack clicked = event.getCurrentItem();
if (clicked == null || clicked.getType() == Material.AIR) return;
int slot = event.getRawSlot();
MenuSession session = menuSessionMap.get(player.getUniqueId());
if (session == null) return;
int page = session.page;
List<ShopItem> items = SHOP_ITEMS.get(cat);
int totalPages = (items.size() - 1) / ITEMS_PER_PAGE + 1;
if (clicked.getType() == Material.ARROW) {
if (clicked.getItemMeta().getDisplayName().contains("上一页") && page > 0) {
openShopMenu(player, cat, page - 1);
} else if (clicked.getItemMeta().getDisplayName().contains("下一页") && page < totalPages - 1) {
openShopMenu(player, cat, page + 1);
}
return;
}
if (clicked.getType() == Material.BARRIER) {
openMainMenu(player);
return;
}
int itemIndex = page * ITEMS_PER_PAGE + (slot - 9);
if (itemIndex >= 0 && itemIndex < items.size()) {
ShopItem si = items.get(itemIndex);
if (event.getClick() == ClickType.LEFT) {
if (hasItems(player, si.material, si.amount)) {
removeItems(player, si.material, si.amount);
addExp(player, si.sellExp);
player.sendMessage("§a出售成功!获得§e" + si.sellExp + "§a经验点。");
} else {
player.sendMessage("§c你背包中没有足够的 " + si.name + "!");
}
} else if (event.getClick() == ClickType.RIGHT) {
if (getTotalExp(player) >= si.buyExp) {
if (player.getInventory().firstEmpty() != -1) {
addExp(player, -si.buyExp);
player.getInventory().addItem(new ItemStack(si.material, si.amount));
player.sendMessage("§b收购成功!消耗§e" + si.buyExp + "§b经验点,获得 " + si.amount + " 个 " + si.name + "。");
} else {
player.sendMessage("§c你的背包已满,无法收购!");
}
} else {
player.sendMessage("§c你的经验点不足,无法收购!");
}
}
}
return;
}
}
}
private static class MenuSession {
public final ShopCategory category;
public final int page;
public MenuSession(ShopCategory category, int page) {
this.category = category;
this.page = page;
}
}
private boolean hasItems(Player player, Material mat, int amount) {
int count = 0;
for (ItemStack is : player.getInventory().getContents()) {
if (is != null && is.getType() == mat) count += is.getAmount();
if (count >= amount) return true;
}
return false;
}
private void removeItems(Player player, Material mat, int amount) {
int left = amount;
ItemStack[] contents = player.getInventory().getContents();
for (int i = 0; i < contents.length; i++) {
ItemStack is = contents[i];
if (is != null && is.getType() == mat) {
if (is.getAmount() > left) {
is.setAmount(is.getAmount() - left);
break;
} else {
left -= is.getAmount();
contents[i] = null;
}
}
if (left <= 0) break;
}
player.getInventory().setContents(contents);
}
private int getTotalExp(Player player) {
return player.getTotalExperience();
}
private void addExp(Player player, int exp) {
int total = getTotalExp(player) + exp;
if (total < 0) total = 0;
player.setTotalExperience(total);
}
}