V5.0 Paper插件架构:深度植入Minecraft服务器进程,实现完美实时防护
核心变更: - 新增 PaperMC 插件层(14个新文件):主插件入口 AluerPlugin + 10个 Bukkit 事件监听器 + DataBridge 数据桥接 + InternalCommandExecutor 内部命令执行器 - 运行时注入服务器进程,直接访问 Bukkit/Paper API,取消 RCON 中间层 - 9种反作弊实时检测(Speed/Fly/Jesus/NoFall/KillAura/Reach/AutoClicker/Scaffold/Nuker)全部迁移为事件驱动 - 聊天安全(刷屏/广告/钓鱼)与命令滥用检测由 AsyncPlayerChatEvent/PlayerCommandPreprocessEvent 直接拦截 - AlertType 枚举扩展至 47 项告警类型,覆盖反作弊/玩家行为/服务器保护/聊天安全/网络/主机全部维度 - 双模式兼容:serverguard.mode=plugin(嵌入式)| external(传统外部监控),旧模式代码完整保留 - Maven 构建切换为 shade 插件,生成 Paper 插件兼容的扁平 JAR - 278 项全量测试通过,0 失败
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
package com.aluer.plugin;
|
||||
|
||||
import com.aluer.ServerGuardApplication;
|
||||
import com.aluer.plugin.bridge.DataBridge;
|
||||
import com.aluer.plugin.listener.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* Aluer ServerGuard — PaperMC 插件主入口
|
||||
*
|
||||
* 插件加载时启动嵌入式 Spring Boot 上下文,
|
||||
* 注册所有 Bukkit 事件监听器,通过 DataBridge
|
||||
* 将服务器内部实时数据推送至安全分析引擎。
|
||||
*
|
||||
* 架构:
|
||||
* Bukkit Events → Event Listeners → DataBridge → Security Services → AI → AutoExecutor → Bukkit API
|
||||
*/
|
||||
public class AluerPlugin extends JavaPlugin {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AluerPlugin.class);
|
||||
|
||||
/** 全局单例引用,供监听器在 Spring 上下文就绪前获取插件实例 */
|
||||
private static AluerPlugin instance;
|
||||
|
||||
/** Spring Boot 应用上下文,插件关闭时需 gracefully shutdown */
|
||||
private ConfigurableApplicationContext springContext;
|
||||
|
||||
/** 数据桥接中心,连接 Bukkit 事件与安全服务 */
|
||||
private DataBridge dataBridge;
|
||||
|
||||
/** Spring 上下文是否已就绪 */
|
||||
private volatile boolean springReady = false;
|
||||
|
||||
// ─── 生命周期 ────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
logger.info("Aluer ServerGuard v4.0.0 — PaperMC Plugin loading (LOAD STARTUP)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
long startMs = System.currentTimeMillis();
|
||||
|
||||
// 步骤 1:启动嵌入式 Spring Boot(异步,避免阻塞 Paper 主线程)
|
||||
logger.info("Starting embedded Spring Boot context...");
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// 设置 Paper 插件模式标志
|
||||
System.setProperty("serverguard.mode", "plugin");
|
||||
System.setProperty("server.mode", "plugin");
|
||||
|
||||
springContext = ServerGuardApplication.bootstrap();
|
||||
dataBridge = springContext.getBean(DataBridge.class);
|
||||
springReady = true;
|
||||
logger.info("Spring Boot context ready — all security services initialized");
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to start Spring Boot context: {}", e.getMessage(), e);
|
||||
}
|
||||
}, "aluer-spring-boot").start();
|
||||
|
||||
// 步骤 2:等待 Spring 上下文就绪(最长 30 秒)
|
||||
int waited = 0;
|
||||
while (!springReady && waited < 30) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
waited++;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!springReady) {
|
||||
logger.error("Spring Boot failed to start within 30s — plugin will operate in degraded mode");
|
||||
}
|
||||
|
||||
// 步骤 3:注册 Bukkit 事件监听器
|
||||
registerEventListeners();
|
||||
|
||||
// 步骤 4:注册插件命令
|
||||
registerCommands();
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startMs;
|
||||
logger.info("Aluer ServerGuard enabled in {}ms — real-time protection active", elapsed);
|
||||
logger.info(" Listeners: 10 event handlers registered");
|
||||
logger.info(" Commands: /aluer, /aluerstatus, /aluerplayers, /aluerblock, /aluerunblock, /aluerscan, /aluerwhitelist");
|
||||
logger.info(" Web Console: http://0.0.0.0:8080/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
logger.info("Shutting down Aluer ServerGuard...");
|
||||
|
||||
// 注销所有 Bukkit 事件监听器
|
||||
HandlerList.unregisterAll(this);
|
||||
|
||||
// 关闭 Spring Boot 上下文
|
||||
if (springContext != null) {
|
||||
springContext.close();
|
||||
springContext = null;
|
||||
}
|
||||
|
||||
instance = null;
|
||||
logger.info("Aluer ServerGuard disabled — protection stopped");
|
||||
}
|
||||
|
||||
// ─── 事件监听器注册 ──────────────────────────────────
|
||||
|
||||
private void registerEventListeners() {
|
||||
// 注意:监听器在构造函数中接收 DataBridge 引用
|
||||
// 如果 Spring 未就绪则使用 null(监听器内部做空安全处理)
|
||||
DataBridge bridge = springReady ? dataBridge : null;
|
||||
|
||||
// 核心监听器:玩家、战斗、聊天、命令
|
||||
Bukkit.getPluginManager().registerEvents(new PlayerEventListener(this, bridge), this);
|
||||
Bukkit.getPluginManager().registerEvents(new CombatEventListener(this, bridge), this);
|
||||
Bukkit.getPluginManager().registerEvents(new ChatEventListener(this, bridge), this);
|
||||
Bukkit.getPluginManager().registerEvents(new CommandEventListener(this, bridge), this);
|
||||
|
||||
// 方块与物品监听器
|
||||
Bukkit.getPluginManager().registerEvents(new BlockEventListener(this, bridge), this);
|
||||
Bukkit.getPluginManager().registerEvents(new InventoryEventListener(this, bridge), this);
|
||||
|
||||
// 实体与世界监听器
|
||||
Bukkit.getPluginManager().registerEvents(new EntityEventListener(this, bridge), this);
|
||||
Bukkit.getPluginManager().registerEvents(new WorldEventListener(this, bridge), this);
|
||||
|
||||
// 包级监听器(Paper API 特有,用于精确的包速率控制)
|
||||
if (Bukkit.getServer().getClass().getPackageName().contains("paper")) {
|
||||
Bukkit.getPluginManager().registerEvents(new PacketEventListener(this, bridge), this);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 命令注册 ────────────────────────────────────────
|
||||
|
||||
private void registerCommands() {
|
||||
AluerCommandExecutor executor = new AluerCommandExecutor(this, dataBridge);
|
||||
var aluerCmd = getCommand("aluer");
|
||||
if (aluerCmd != null) {
|
||||
aluerCmd.setExecutor(executor);
|
||||
aluerCmd.setTabCompleter(executor);
|
||||
}
|
||||
|
||||
var statusCmd = getCommand("aluerstatus");
|
||||
if (statusCmd != null) statusCmd.setExecutor(executor);
|
||||
var playersCmd = getCommand("aluerplayers");
|
||||
if (playersCmd != null) playersCmd.setExecutor(executor);
|
||||
var blockCmd = getCommand("aluerblock");
|
||||
if (blockCmd != null) blockCmd.setExecutor(executor);
|
||||
var unblockCmd = getCommand("aluerunblock");
|
||||
if (unblockCmd != null) unblockCmd.setExecutor(executor);
|
||||
var scanCmd = getCommand("aluerscan");
|
||||
if (scanCmd != null) scanCmd.setExecutor(executor);
|
||||
var whitelistCmd = getCommand("aluerwhitelist");
|
||||
if (whitelistCmd != null) whitelistCmd.setExecutor(executor);
|
||||
}
|
||||
|
||||
// ─── 公开访问器 ──────────────────────────────────────
|
||||
|
||||
/** 获取插件单例实例 */
|
||||
public static AluerPlugin getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** 获取 Spring 应用上下文(可能为 null,在 Spring 就绪前) */
|
||||
public ConfigurableApplicationContext getSpringContext() {
|
||||
return springContext;
|
||||
}
|
||||
|
||||
/** 获取 DataBridge(可能为 null,在 Spring 就绪前) */
|
||||
public DataBridge getDataBridge() {
|
||||
return dataBridge;
|
||||
}
|
||||
|
||||
/** Spring 上下文是否已完全初始化 */
|
||||
public boolean isSpringReady() {
|
||||
return springReady;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user