分类: Minecraft 插件

用 AI 团队打造 Minecraft 服务器#2一个插件装下 13 个模块!core 结构与"1000029 伤害"事件 🧩

本文译自韩语原文。

要点速览

这个服务器只有一个插件 jar,里面装着 core 和 13 个模块。模块之间不直接调用,只通过 core 的服务相连。本文介绍这种结构下实际出现的两个 bug,以及不关服就能重新读取配置的重载、重启功能。

  • Paper 1.21.11 · Java · 1 个插件 jar = core + 13 个模块 · 2026-09-29~30 实际修复
  • 模块之间不直接依赖,只通过 core 服务(接口)相连 —— 这正是各团队能并行开发的原因
  • 违反权限节点前缀规则就让整个模块无法启用,这是刻意设计的安全机制
  • 伤害 1000029 = "剩余生命值 29 + 死亡处理用的 1,000,000"。错的不是计算,而是显示
目录9 项

大家好!我是 Mojangcam 😎

上一篇 #1 介绍了让 Claude 当组长、把 15 个定时任务当组员来干活的结构。这一篇讲的是这些团队所做的插件本身的结构。

我们的服务器里,自己写的插件只有一个 jar 文件。等级、战斗、技能、任务、商店、怪物等功能,在这个 jar 里被拆成了 13 个模块。这一篇会整理

  • 🧩 为什么要设计成 core + 模块的结构
  • 🔒 一个权限名就让两个模块整体无法启用的事件
  • 💥 击杀怪物时伤害显示成 1000029 的事件
  • 🔄 不关服就能重新读取配置的 /리로드(重载),以及能自动重新启动的 /재시작(重启)

这几件事。

怪物头顶浮现出绿色巨大伤害数字 1000029 的游戏画面


📌 准备工作(环境)

  • 服务器:Paper 1.21.11,Java 21 及以上
  • 构建:Gradle 多项目(每个模块一个子项目 → 最后打包成一个 jar)
  • 数据库:MariaDB(保存游戏进度)
  • 外部插件只用最少的几个:LuckPerms(权限)· EssentialsX · WorldEdit

📌 第 1 步 - 为什么是"一个 jar + 13 个模块" 🧠

一开始我也想过每个功能单独做一个插件。可是等级、战斗、技能、物品之间要不停地互相传递数字。插件一旦分开,加载顺序、版本对齐、API 共享全都会变成麻烦事。

所以我们这样定了下来。

层 职责
core 配置文件 · 消息 · 数据库连接 · 权限注册 · 命令注册 · 服务注册表 · 虚拟生命值 · HUD
13 个模块 economy · quest · job · level · combat · skill · item · companion · world · mob · log · storage 等
规则 模块不直接 import 其他模块的类。需要的功能只通过 core 里的接口(服务)获取

比如战斗模块想知道武器攻击力时,不会去调用物品模块,而是找到注册在 core 里的 ItemService 来用。物品模块关掉的话,只是没有这个服务而已,战斗模块会用默认值照常运行。

多亏了这条规则,13 个团队才能同时开发。每个团队只要相信接口去干活就行。


📌 第 2 步 - 一个权限名让整个模块无法启用的事件 🔒

启动服务器后,日志里出现了这样的内容(节选)。

文本
[MyServer] quest 모듈 켜기 실패: 권한 노드는 'myserver.quest.' 로 시작해야 합니다 — myserver.qnpc.console
[MyServer] world 모듈 켜기 실패: 권한 노드는 'myserver.world.' 로 시작해야 합니다 — myserver.region.admin

core 的权限注册函数会检查 "权限名必须以 myserver.<모듈>.(模块名)开头" 这条规则,违反就抛出异常。一旦抛出异常,这个模块就不会启用。

任务组给 NPC 命令用了 myserver.qnpc.…,世界组给区域保护用了 myserver.region.…。这些名字人看着也挺像回事,所以审查时漏掉了。

我们逐个拆开看看 💡

  • 为什么这么严格?:模块有 13 个的话,权限名很容易撞车。强制前缀之后,在 LuckPerms 里一行 myserver.quest.* 就能把整个模块的权限一次性给出去。
  • 为什么不是警告,而是直接关掉模块?:如果权限注册错了还照常运行,可能会发生管理员专用命令对普通玩家开放的事故。安全机制还是确定地停下来更好。

修复只是改了两个名字就完事了。不过为了防止同样的事故,我们在组长流程里加了一行合并前自动检查。

终端
# 在 module/<团队> 分支中查找违反前缀规则的权限节点(结果为空才算通过)
m=quest
git grep -hoE 'registerPermission\([^;]*' module/$m -- "$m/src/main" \
  | grep -oE '"myserver\.[a-z_]+\.' | awk -F. -v m=$m '$2!=m'

📌 第 3 步 - 伤害 1000029 事件 💥

在游戏里击杀怪物的那一刻,头顶冒出了 1000029 这种离谱的数字。但怪物并不是一击毙命。前面几次攻击的数字都正常,只有最后一击不对劲。

原因:"虚拟生命值"和"确保击杀"

这个服务器的生命值会涨到几千甚至几万。原版生命值(最大 1024)不够用,所以 core 另外管理一套虚拟生命值。虚拟生命值归 0 时,core 还得在原版那边也确实把怪物杀死,当时是这样写的。

Java
// core:虚拟生命值归 0 时,在原版里也确保杀死
e.damage(e.getHealth() + 1_000_000, damageSource);   // 死亡处理用的内部伤害

在原版看来,这就是挨了"剩余生命值 + 1,000,000"的伤害。而负责显示伤害数字的战斗模块连这个内部伤害事件也收到了,并原样显示了出来。剩余原版生命值 29 + 1,000,000 = 1000029。数字完全对得上 😂

修复:不显示死亡处理用的伤害

这个内部伤害的伤害类型是 GENERIC_KILL。我们在战斗模块里只加了一行。

Java
// combat:伤害数字显示监听器 (MONITOR)
if (event.getDamageSource().getDamageType() == DamageType.GENERIC_KILL) return; // 死亡处理用的内部伤害不显示为数字
double shown = event.getFinalDamage();

实际的伤害计算从一开始就是正常的,这是一个只有显示出错的 bug。这种 bug 在游戏里看一眼就能发现,但很难用单元测试抓到。第 1 篇说过的"人负责进游戏看、然后说出来"这个角色,在这里大显身手了。


📌 第 4 步 - 不关服修改配置:/리로드(重载)· /재시작(重启) 🔄

AI 团队一天要改好几次配置和 jar,每次都关服再开服实在太麻烦了。所以我们在 core 里加了两样东西。

命令 作用
/리로드 (/myserver reload) 重新读取 core → 所有已启用模块的配置文件,并按模块给出 ✓/✗ 汇总。配置有误时只有那个模块失败,并保留之前的配置
/리로드 level 只重新读取这个模块
/재시작 60 倒计时 60 秒(聊天 + Boss 栏)后关闭服务器 → 自动重新启动
(自动) 配置文件一变就自动重新读取,plugins/update 里放进新 jar 时通知管理员

"自动重新启动"光靠服务器端的代码做不到。插件会在关闭前创建一个标记文件,启动服务器的批处理文件看到这个文件就会再次启动。

命令提示符
@echo off
chcp 65001 > nul
cd /d "%~dp0"
:loop
if exist "plugins\MyServer\.restart" del /q "plugins\MyServer\.restart"
java -Xmx8G -jar server.jar nogui
if exist "plugins\MyServer\.restart" (
  echo 재시작 요청 확인 - 5초 뒤 다시 켭니다. 중지하려면 Ctrl+C
  timeout /t 5
  goto loop
)
echo 서버가 종료되었습니다.
pause

我们逐个拆开看看 💡

  • .restart 文件:由 /재시작 创建。如果直接用 /stop 关服,就没有这个文件,所以不会重新启动。
  • 在循环开头删除:防止上一次重启留下的痕迹导致无限重启。
  • 内存(-Xmx):请根据服务器配置修改。

📌 常见错误

  1. 模块无法启用 —— "权限节点必须以 … 开头" 原因:违反了权限名前缀规则 → 解决:把名字改成 myserver.<모듈>.…(模块名)
  2. /리로드 之后只有某个模块显示 ✗ 原因:该模块的配置 JSON 有语法错误 → 解决:看日志里的行号改好后再执行一次 /리로드。在此期间它会继续用之前的配置运行
  3. 重启后服务器没有启动 原因:没用批处理文件,而是直接用 java -jar 启动 → 解决:用带循环的批处理文件启动

📌 总结

今天整理了插件结构和两个真实事件。

  • 一个 jar + 13 个模块,模块之间只通过 core 服务相连
  • 权限前缀规则是直接关掉模块的安全机制 + 合并前自动检查
  • 1000029 是死亡处理用的内部伤害被显示成了数字
  • 有了 /리로드 · /재시작,即使 AI 团队频繁修改,服务器运维也轻松多了

下一篇讲数值平衡。会聊到把生命值和伤害一次性放大 10 倍的方法、"30 级只要 12 小时"的经验曲线,以及策划组 AI 模拟 6 个职业后找到的意外原因。敬请期待 🙌

本文由我确定方向,并与 Claude 一起整理。这个服务器是个人项目,不是 Minecraft 官方内容,与 Mojang、Microsoft 没有关系。

连载 · 共 5 篇中的第 2 篇

用 AI 团队打造 Minecraft 服务器

  1. #11 名 AI 组长 + 15 名组员,打造 MMORPG 插件的结构!🤖
  2. #2一个插件装下 13 个模块!core 结构与"1000029 伤害"事件 🧩当前文章
  3. #3数值 ×10、12 小时经验曲线、6 个职业模拟!📊
  4. #4ChatGPT 画图、Claude 审核的资源包流水线!🎨
  5. #5用 Discord 机器人运营开发团队!决策论坛·命令列表·资源包频道 🤝

作者

Mojangcam

亲手写代码、跑服务器、解决卡住的报错,把一路学到的东西记录下来的开发与 IT 实战博客