feat: 新增SN防伪系统,接入四类道具签发、拾取/合成/熔炼探查、销毁解绑与PHP目录同步
This commit is contained in:
@@ -1765,6 +1765,25 @@ public class AreaGUIManager implements Listener {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ★ SN 管控:1人同种类仅限1个
|
||||
if (plugin.getSnManager() != null
|
||||
&& plugin.getSnManager().isBlocked(
|
||||
p, SnManager.TYPE_WAND)) {
|
||||
p.sendMessage("§e你已有区域选择工具的有效登记,"
|
||||
+ "旧SN未注销前不能重新申领");
|
||||
areaProtect.wandCooldownMap.put(p.getUniqueId(), now);
|
||||
return;
|
||||
}
|
||||
if (plugin.getSnManager() != null) {
|
||||
String sn = plugin.getSnManager().applySn(
|
||||
p, SnManager.TYPE_WAND, "区域选择工具");
|
||||
if (sn == null) {
|
||||
areaProtect.wandCooldownMap.put(p.getUniqueId(), now);
|
||||
return;
|
||||
}
|
||||
plugin.getSnManager().writeSn(
|
||||
wand, sn, SnManager.TYPE_WAND);
|
||||
}
|
||||
p.getInventory().addItem(wand);
|
||||
// ★ GUI模式不发送聊天消息
|
||||
areaProtect.wandCooldownMap.put(p.getUniqueId(), now);
|
||||
|
||||
@@ -6628,12 +6628,31 @@ public class AreaProtection implements Listener {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// ★ SN 管控:1人同种类仅限1个
|
||||
if (plugin.getSnManager() != null
|
||||
&& plugin.getSnManager().isBlocked(
|
||||
p, SnManager.TYPE_WAND)) {
|
||||
p.sendMessage("§c§l[防护] §f你已有区域选择工具的有效登记,"
|
||||
+ "旧SN未注销前不能重新申领");
|
||||
wandCooldownMap.put(p.getUniqueId(), now);
|
||||
return true;
|
||||
}
|
||||
ItemStack tool = new ItemStack(WAND);
|
||||
ItemMeta meta = tool.getItemMeta();
|
||||
meta.setDisplayName("§a§l区域选择工具");
|
||||
meta.setLore(Arrays.asList(
|
||||
"§7左键: 位置1", "§7右键: 位置2"));
|
||||
tool.setItemMeta(meta);
|
||||
if (plugin.getSnManager() != null) {
|
||||
String sn = plugin.getSnManager().applySn(
|
||||
p, SnManager.TYPE_WAND, "区域选择工具");
|
||||
if (sn == null) {
|
||||
wandCooldownMap.put(p.getUniqueId(), now);
|
||||
return true;
|
||||
}
|
||||
plugin.getSnManager().writeSn(
|
||||
tool, sn, SnManager.TYPE_WAND);
|
||||
}
|
||||
p.getInventory().addItem(tool);
|
||||
p.sendMessage("§a§l[防护] §f已获取选择工具");
|
||||
wandCooldownMap.put(p.getUniqueId(), now);
|
||||
|
||||
@@ -110,7 +110,25 @@ public class LandRecordManager implements Listener {
|
||||
|
||||
/** 直接发放一枚回声碎片给玩家(GUI 菜单调用) */
|
||||
public void giveEchoShard(Player p) {
|
||||
// ★ SN 管控:1人同种类仅限1个
|
||||
if (plugin.getSnManager() != null
|
||||
&& plugin.getSnManager().isBlocked(
|
||||
p, SnManager.TYPE_ECHO)) {
|
||||
p.sendMessage("§c§l[回声碎片] §f你已有回声碎片的有效登记,"
|
||||
+ "旧SN未注销前不能重新申领");
|
||||
return;
|
||||
}
|
||||
ItemStack shard = createEchoShard();
|
||||
if (plugin.getSnManager() != null) {
|
||||
String sn = plugin.getSnManager().applySn(
|
||||
p, SnManager.TYPE_ECHO, "回声碎片");
|
||||
if (sn == null) {
|
||||
p.sendMessage("§c§l[回声碎片] §f申领被SN系统拒绝");
|
||||
return;
|
||||
}
|
||||
plugin.getSnManager().writeSn(
|
||||
shard, sn, SnManager.TYPE_ECHO);
|
||||
}
|
||||
HashMap<Integer, ItemStack> left =
|
||||
p.getInventory().addItem(shard);
|
||||
if (!left.isEmpty()) {
|
||||
|
||||
@@ -155,6 +155,7 @@ public class Main extends JavaPlugin
|
||||
// 在 Main.java 字段声明区域(bondManager 附近)添加:
|
||||
// 在 bondManager 字段附近添加:
|
||||
private BondPrinter bondPrinter;
|
||||
private SnManager snManager;
|
||||
private OrderManager orderManager;
|
||||
|
||||
public OrderManager getOrderManager() {
|
||||
@@ -591,6 +592,17 @@ public class Main extends JavaPlugin
|
||||
getCommand("cypay").setTabCompleter(cypayCommand);
|
||||
}
|
||||
bondPrinter = new BondPrinter(this);
|
||||
// ===== SN 防刷系统:建表 + 注册事件 =====
|
||||
try {
|
||||
snManager = new SnManager(this);
|
||||
snManager.init();
|
||||
getServer().getPluginManager()
|
||||
.registerEvents(snManager, this);
|
||||
} catch (Throwable t) {
|
||||
snManager = null;
|
||||
getLogger().severe("[SN] 初始化失败: " + t.getMessage());
|
||||
t.printStackTrace();
|
||||
}
|
||||
// cdkManager.loadCDKsFromDir();
|
||||
//14 ====商店====
|
||||
// ★ 构造器内已加载完毕,此处重复
|
||||
@@ -757,6 +769,10 @@ public class Main extends JavaPlugin
|
||||
return bondPrinter;
|
||||
}
|
||||
|
||||
public SnManager getSnManager() {
|
||||
return snManager;
|
||||
}
|
||||
|
||||
public ShopManager getShopManager() {
|
||||
return shopManager;
|
||||
}
|
||||
@@ -2716,6 +2732,34 @@ public class Main extends JavaPlugin
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SN 打标:为即将发放的物品登记 SN 并写入物品。
|
||||
*
|
||||
* @return true = 可以发放;false = 被 SN 管控拒绝(调用方放弃发放)
|
||||
*/
|
||||
private boolean snTag(Player p, ItemStack it,
|
||||
String type, String what) {
|
||||
if (snManager == null) return true;
|
||||
String sn = snManager.applySnQuiet(p, type, what);
|
||||
if (sn == null) {
|
||||
// 冷静期 / 同种类已有有效登记 → 拒绝发放
|
||||
if (snManager.isBlocked(p, type)) return false;
|
||||
// 数据库异常等:放行但不打标,避免卡死正常发放
|
||||
getLogger().warning("[SN] 打标失败: " + what
|
||||
+ " -> " + p.getName());
|
||||
return true;
|
||||
}
|
||||
snManager.writeSn(it, sn, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 轻点:清理某玩家背包内无 SN 的插件自定义物品并补发带 SN 版本 */
|
||||
private void snSweep(CommandSender sender, Player target) {
|
||||
int[] r = snManager.auditAndResend(target, false);
|
||||
sender.sendMessage("§a[SN] " + target.getName()
|
||||
+ ":清理 §f" + r[0] + " §a件,补发 §f" + r[1] + " §a件");
|
||||
}
|
||||
|
||||
private static final String MENU_SNOWBALL_TAG =
|
||||
"sdf1_menu";
|
||||
|
||||
@@ -2745,6 +2789,12 @@ public class Main extends JavaPlugin
|
||||
return;
|
||||
}
|
||||
|
||||
// ★ SN 管控:1人同种类仅限1个,旧SN未注销/冷静期未过不再发放
|
||||
if (snManager != null
|
||||
&& snManager.isBlocked(p, SnManager.TYPE_MENU)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack customIcon =
|
||||
menuIconMgr != null ? menuIconMgr.getIcon(p) : null;
|
||||
// getLogger().info("[菜单] " + name + " 自定义图标: " + (customIcon != null ? customIcon.getType().name() : "null"));
|
||||
@@ -2779,6 +2829,10 @@ public class Main extends JavaPlugin
|
||||
cm.setLore(cmLore);
|
||||
customIcon.setItemMeta(cm);
|
||||
}
|
||||
if (!snTag(p, customIcon,
|
||||
SnManager.TYPE_MENU, "自定义菜单图标")) {
|
||||
return;
|
||||
}
|
||||
int slot = p.getInventory()
|
||||
.firstEmpty();
|
||||
if (slot >= 0) {
|
||||
@@ -2804,6 +2858,9 @@ public class Main extends JavaPlugin
|
||||
im.setLore(lore);
|
||||
snow.setItemMeta(im);
|
||||
}
|
||||
if (!snTag(p, snow, SnManager.TYPE_MENU, "雪球菜单")) {
|
||||
return;
|
||||
}
|
||||
int slot = p.getInventory()
|
||||
.firstEmpty();
|
||||
if (slot >= 0) {
|
||||
@@ -2831,6 +2888,12 @@ public class Main extends JavaPlugin
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ★ SN 管控:1人同种类仅限1个,旧SN未注销/冷静期未过不再发放
|
||||
if (snManager != null
|
||||
&& snManager.isBlocked(p, SnManager.TYPE_MENU)) {
|
||||
return;
|
||||
}
|
||||
ItemStack snow = new ItemStack(
|
||||
Material.SNOWBALL);
|
||||
ItemMeta im = snow.getItemMeta();
|
||||
@@ -2844,6 +2907,9 @@ public class Main extends JavaPlugin
|
||||
im.setLore(lore);
|
||||
snow.setItemMeta(im);
|
||||
}
|
||||
if (!snTag(p, snow, SnManager.TYPE_MENU, "雪球菜单")) {
|
||||
return;
|
||||
}
|
||||
int slot = p.getInventory()
|
||||
.firstEmpty();
|
||||
if (slot >= 0) {
|
||||
@@ -5982,6 +6048,46 @@ public class Main extends JavaPlugin
|
||||
bondPrinter.printAll(sender);
|
||||
return true;
|
||||
}
|
||||
// ===== /printer item [玩家名] → 导出 SN 记录 =====
|
||||
if (args.length >= 1
|
||||
&& "item".equalsIgnoreCase(args[0])) {
|
||||
if (snManager == null) {
|
||||
sender.sendMessage("§cSN系统未初始化");
|
||||
return true;
|
||||
}
|
||||
String snTarget = args.length >= 2
|
||||
? args[1] : null;
|
||||
sender.sendMessage("§e正在导出SN记录...");
|
||||
snManager.printSnRecords(sender, snTarget);
|
||||
return true;
|
||||
}
|
||||
// ===== /printer sweep [玩家名] → 一次性轻点补发 =====
|
||||
if (args.length >= 1
|
||||
&& "sweep".equalsIgnoreCase(args[0])) {
|
||||
if (snManager == null) {
|
||||
sender.sendMessage("§cSN系统未初始化");
|
||||
return true;
|
||||
}
|
||||
if (args.length >= 2) {
|
||||
Player tp = Bukkit.getPlayer(args[1]);
|
||||
if (tp == null) {
|
||||
sender.sendMessage("§c玩家不在线: " + args[1]);
|
||||
return true;
|
||||
}
|
||||
snSweep(sender, tp);
|
||||
return true;
|
||||
}
|
||||
sender.sendMessage("§e正在轻点全体在线玩家...");
|
||||
int removed = 0, resent = 0;
|
||||
for (Player tp : Bukkit.getOnlinePlayers()) {
|
||||
int[] r = snManager.auditAndResend(tp, false);
|
||||
removed += r[0];
|
||||
resent += r[1];
|
||||
}
|
||||
sender.sendMessage("§a[SN] 轻点完成:清理 §f" + removed
|
||||
+ " §a件,补发 §f" + resent + " §a件");
|
||||
return true;
|
||||
}
|
||||
if (args.length == 1) {
|
||||
// 打印指定玩家
|
||||
String target = args[0];
|
||||
@@ -5992,7 +6098,8 @@ public class Main extends JavaPlugin
|
||||
return true;
|
||||
}
|
||||
sender.sendMessage(
|
||||
"§7用法: /printer [玩家名]");
|
||||
"§7用法: /printer [玩家名] | /printer item [玩家名]"
|
||||
+ " | /printer sweep [玩家名]");
|
||||
return true;
|
||||
}
|
||||
// ===== /chat 独立命令 =====
|
||||
|
||||
@@ -485,10 +485,27 @@ public class PVPManager implements Listener {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has) {
|
||||
p.getInventory()
|
||||
.addItem(createTool());
|
||||
if (has) return;
|
||||
// ★ SN 管控:1人同种类仅限1个
|
||||
if (plugin.getSnManager() != null
|
||||
&& plugin.getSnManager().isBlocked(
|
||||
p, SnManager.TYPE_PVP)) {
|
||||
p.sendMessage("§c[PVP] 你已有PVP圈地棒的有效登记,"
|
||||
+ "旧SN未注销前不能重新申领");
|
||||
return;
|
||||
}
|
||||
ItemStack tool = createTool();
|
||||
if (plugin.getSnManager() != null) {
|
||||
String sn = plugin.getSnManager().applySn(
|
||||
p, SnManager.TYPE_PVP, "PVP圈地棒");
|
||||
if (sn == null) {
|
||||
p.sendMessage("§c[PVP] 申领被SN系统拒绝");
|
||||
return;
|
||||
}
|
||||
plugin.getSnManager().writeSn(
|
||||
tool, sn, SnManager.TYPE_PVP);
|
||||
}
|
||||
p.getInventory().addItem(tool);
|
||||
}
|
||||
|
||||
// ===== 边框粒子 =====
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2012,6 +2012,15 @@ public class WebManager {
|
||||
catch (Exception e) { landSyncFailCount++; }
|
||||
}
|
||||
|
||||
// ★ SN 防刷同步(任务6):手持上报 + 事件队列 + 命令拉取
|
||||
try {
|
||||
SnManager snm = plugin.getSnManager();
|
||||
if (snm != null) snm.tickSync();
|
||||
} catch (Throwable t) {
|
||||
plugin.getLogger().warning(
|
||||
"[SN] 同步异常: " + t.getMessage());
|
||||
}
|
||||
|
||||
// 全量批处理同步(仅在nextSyncTime到达时执行)
|
||||
if (now >= nextSyncTime) {
|
||||
try { doActiveSyncBatch(); }
|
||||
|
||||
Reference in New Issue
Block a user