Spigot 1.8_R3起床战争插件商店背包物品扣除异常问题求助
Spigot背包物品指定数量扣除解决方案
现有代码问题分析
- 空指针错误原因:
Inventory#getContents()返回的数组包含背包空槽位,对应值为null,遍历过程中未做非空判断直接调用invItem.getType()会触发NPE。 - 扣除逻辑错误:
- 原
Inventory#remove()方法仅能匹配完整相等的ItemStack(物品类型、数量、元数据完全一致),无法拆分堆叠扣除 - 后续编写的逻辑未单独存储待扣除总数量,循环过程中修改待扣物品的
amount属性导致计数混乱,且未覆盖堆叠数量刚好等于待扣数量的场景 - 未提前校验玩家背包总资源是否足够,可能出现扣除一半资源后数量不足的异常情况
- 原
实现步骤
- 先读取待扣除的物品类型、总扣除数量
- 遍历玩家背包统计对应物品总数量,判断是否足够扣除,不足直接提示玩家终止操作
- 遍历背包槽位,对非空、类型匹配的物品堆叠进行扣除操作,单独用变量记录剩余待扣数量,扣完即终止循环
- 扣除完成后刷新玩家背包避免客户端显示异常
完整代码
public void removeItemFromInventory(Inventory inv, ItemStack currentItem, Player p) { // 读取配置获取待扣除的物品类型和总数量 Material costType = getResource(Main.plugin.getConfigValue("shop." + currentItem.getTypeId() + ".type")); int totalCost = Integer.parseInt(Main.plugin.getConfigValue("shop." + currentItem.getTypeId() + ".cost")); // 第一步:先统计背包内对应物品总数量,判断是否足够 int totalHas = 0; for (ItemStack invItem : inv.getContents()) { if (invItem != null && invItem.getType() == costType) { // 如果你的资源是自定义物品(带名称、lore),这里要加ItemMeta的匹配判断 totalHas += invItem.getAmount(); } } if (totalHas < totalCost) { p.sendMessage("§c资源不足,无法购买"); return; } // 第二步:开始扣除物品 int remainCost = totalCost; for (ItemStack invItem : inv.getContents()) { // 待扣数量为0直接终止循环 if (remainCost <= 0) { break; } // 空槽、物品类型不匹配直接跳过 if (invItem == null || invItem.getType() != costType) { continue; } // 自定义物品这里同样要加ItemMeta匹配判断 int stackAmount = invItem.getAmount(); if (stackAmount > remainCost) { // 当前堆叠数量大于剩余待扣数,直接减对应数量即可 invItem.setAmount(stackAmount - remainCost); remainCost = 0; } else { // 当前堆叠数量小于等于待扣数,直接清空这个堆叠 invItem.setAmount(0); remainCost -= stackAmount; } } // 刷新背包避免客户端显示不同步 p.updateInventory(); // 重新打开商店 FastShop shop = new FastShop(p); p.closeInventory(); p.openInventory(shop.getInventory()); }
注意事项
- 如果你的服务器用的是带自定义名称、Lore的资源物品(比如改名为「铁」的铁锭),需要在类型判断的位置增加
ItemMeta的相等判断,避免误扣普通铁锭 - 1.8版本
updateInventory()方法是有效的,高版本SpigotAPI可能需要调整背包刷新逻辑
内容的提问来源于stack exchange,提问作者Sysy
相关产品推荐
相关产品推荐

