From 626fbcd591d9841619ceafdbeb5e8d852b64c2ad Mon Sep 17 00:00:00 2001 From: youpaishidifu Date: Thu, 9 Jul 2026 13:32:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=84=E9=AD=94=E4=B9=A6NBT=EF=BC=9A?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E7=A9=BA=E5=A3=B3=E5=85=9C=E5=BA=95=EF=BC=8C?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=A4=B1=E8=B4=A5=E5=88=99=E6=95=B4=E5=8D=95?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E5=B9=B6=E9=80=80=E6=AC=BE=EF=BC=88=E5=90=AB?= =?UTF-8?q?=E5=8D=95=E7=AC=94=E8=B4=AD=E4=B9=B0=E9=80=80=E6=AC=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Sdf1_login/ShopManager.java | 11 +++++-- src/main/java/Sdf1_login/WebManager.java | 38 ++++++++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/main/java/Sdf1_login/ShopManager.java b/src/main/java/Sdf1_login/ShopManager.java index 56dc1be..1d6b08c 100644 --- a/src/main/java/Sdf1_login/ShopManager.java +++ b/src/main/java/Sdf1_login/ShopManager.java @@ -1449,20 +1449,25 @@ public class ShopManager implements Listener { /** * 若传入的附魔书是“空壳”(无存储附魔),则尝试用商品ID权威重建附魔NBT。 * 用于 Web 商城发放附魔书兜底,避免显示名解析失败/ENCHANT_MAP 为空导致空壳。 + * ★ 若 ID 重建也失败(解析失败),返回 null —— 由上层整单取消并退款,绝不发放空壳。 */ public ItemStack ensureEnchantedBookNbt(ItemStack itemStack, String itemId, int amount) { - if (itemStack == null || itemStack.getType() != Material.ENCHANTED_BOOK) return itemStack; + if (itemStack == null) return null; + if (itemStack.getType() != Material.ENCHANTED_BOOK) return itemStack; ItemMeta m = itemStack.getItemMeta(); boolean empty = !(m instanceof EnchantmentStorageMeta) || ((EnchantmentStorageMeta) m).getStoredEnchants().isEmpty(); - if (!empty) return itemStack; + if (!empty) return itemStack; // 已是带附魔的有效书 + // 空壳 → 用商品ID权威重建 ItemStack rebuilt = buildEnchantedBookFromId(itemId); if (rebuilt != null) { rebuilt.setAmount(amount); plugin.getLogger().info("[Shop] 附魔书空壳已用ID重建NBT: " + itemId); return rebuilt; } - return itemStack; + // ★ 解析失败:不再发放空壳,返回 null 交由上层整单取消/退款 + plugin.getLogger().warning("[Shop] 附魔书无法由ID重建(解析失败),取消发放: " + itemId); + return null; } private int parseEnchantLevel(String name, String keyword) { diff --git a/src/main/java/Sdf1_login/WebManager.java b/src/main/java/Sdf1_login/WebManager.java index cdd74d8..897b5dd 100644 --- a/src/main/java/Sdf1_login/WebManager.java +++ b/src/main/java/Sdf1_login/WebManager.java @@ -5918,7 +5918,18 @@ public class WebManager { // ★ 通知玩家购买成功 player.sendMessage("§6[商城] §fWeb购买 §e" + itemId + " x" + itemCount + " §f成功!§c-" + amount + "§f 债券"); player.sendMessage("§6[债券] §f余额: §e" + (newBal + amount) + " §7→ §a" + newBal); - dispatchItemByMaterialOrId(player, itemId, itemCount); + boolean delivered = dispatchItemByMaterialOrId(player, itemId, itemCount); + if (!delivered) { + // ★ 发放失败(附魔书解析失败等)→ 整笔不确认 + 写退款,避免玩家付了钱拿不到东西 + plugin.getLogger().warning("[Web交易] 单笔购买发放失败,发起退款: " + itemId + " 交易#" + txId); + player.sendMessage("§c[商城] §f商品发放失败,已自动退款:§e" + itemId); + try { + writeRefundTransaction(playerName, amount, txId, "单笔购买发放失败:" + itemId, "bond"); + } catch (Exception ex) { + plugin.getLogger().warning("[Web交易] 写入退款记录失败: " + ex.getMessage()); + } + return; // 不 confirm,PHP 端退款 + } } else { plugin.getLogger().info("[Web交易] 玩家离线,保存到离线邮件"); saveOfflineItem(playerName, itemId, itemCount); @@ -6052,8 +6063,13 @@ public class WebManager { } else { for (CartEntry ce : entries) { try { - dispatchItemByMaterialOrId(player, ce.itemId, ce.amount, ce.name); - okItems.add(ce.name != null ? ce.name : ce.itemId); + boolean delivered = dispatchItemByMaterialOrId(player, ce.itemId, ce.amount, ce.name); + if (delivered) { + okItems.add(ce.name != null ? ce.name : ce.itemId); + } else { + // ★ 发放失败(含附魔书解析失败)→ 计入失败列表,触发整单取消+退款 + failedItems.add(ce.itemId); + } } catch (Exception ex) { failedItems.add(ce.itemId); plugin.getLogger().warning("[Web交易] 发放商品异常: " + ce.itemId + " → " + ex.getMessage()); @@ -6232,15 +6248,15 @@ public class WebManager { /** * 通过Material名称或商品ID发放商品(兼容PHP传Material名称的情况) */ - private void dispatchItemByMaterialOrId(Player player, String itemId, int amount) { - dispatchItemByMaterialOrId(player, itemId, amount, null); + private boolean dispatchItemByMaterialOrId(Player player, String itemId, int amount) { + return dispatchItemByMaterialOrId(player, itemId, amount, null); } /** * 发放单个商品(支持按购物车携带的真实显示名重建附魔书等带NBT物品)。 * name 为 PHP 购物车携带的真实显示名(含附魔关键词),用于修正材质匹配取到裸附魔书的问题。 */ - private void dispatchItemByMaterialOrId(Player player, String itemId, int amount, String name) { + private boolean dispatchItemByMaterialOrId(Player player, String itemId, int amount, String name) { try { plugin.getLogger().info("[Web交易] 发放商品(材料匹配): " + itemId + " x" + amount + " 给 " + player.getName()); @@ -6313,6 +6329,7 @@ public class WebManager { // ★ 附魔书空壳兜底(ID权威重建):若上面任一路径给出无附魔的附魔书 // (显示名解析失败、ENCHANT_MAP 为空等),用商品ID(MENDING_I 等)重建NBT。 + // 若重建也失败,ensureEnchantedBookNbt 返回 null —— 不发放空壳,返回 false 触发整单取消/退款。 itemStack = plugin.getShopManager().ensureEnchantedBookNbt(itemStack, itemId, amount); if (itemStack != null) { @@ -6331,16 +6348,21 @@ public class WebManager { } player.sendMessage("§a[Web商城] §f成功购买商品: " + displayName + " x" + amount); plugin.getLogger().info("[Web交易] 商品发放成功"); + return true; } else { - plugin.getLogger().warning("[Web交易] 商品不存在: " + itemId + "(Material或ID均无匹配)"); - player.sendMessage("§c[Web商城] §f商品不存在: " + itemId); + // ★ 发放失败:附魔书解析失败或商品不存在 → 返回 false,由上层整单取消/退款 + plugin.getLogger().warning("[Web交易] 商品无法发放(附魔书解析失败或商品不存在): " + itemId); + player.sendMessage("§c[Web商城] §f商品发放失败(解析失败): " + itemId); + return false; } } else { plugin.getLogger().warning("[Web交易] ShopManager未初始化"); + return false; } } catch (Exception e) { plugin.getLogger().warning("[Web交易] 发放商品失败: " + e.getMessage()); e.printStackTrace(); + return false; } }