NeoForge 模组(Kotlin 实现),把 Minecraft Java 服务器接入游戏社区平台(core)。
与 paper-plugin 同协议、同 6 轴雷达 metric,行为/反馈尽量对齐。
两个项目的差异都在加载器封装层(事件总线、命令系统、玩家对象),核心逻辑(HTTP 长轮询、stats 读取、CommandRouter 分支)几乎可以逐行对比。
- 长轮询:从平台拉取下行命令(踢人 / 白名单 / 广播 / 玩家通知 / 站内聊天回灌 / 排行 / 按需查 stats)
- 心跳上报:每 30s 上报在线人数与玩家列表
- 玩家事件:加入/离开实时 POST
- 账号绑定:
/axo bind <CODE>走/api/srv/binding.request - stats 按需查 + 拉模式排行:读
<world>/stats/<uuid>.json,与 paper-plugin 一致(PLAN §10.2) - 聊天桥:游戏内聊天 → 平台
/api/srv/chat.message;平台广播 →[Web] sender content - 管理员命令:
admin.command.run走 vanilla Brigadier,捕获输出回报 - 玩家命令:
/axo web(社区网址)、/axo docs(浏览本地文档)
| 依赖 | 版本 |
|---|---|
| Minecraft | 1.21.x(默认 1.21.1,可通过 gradle 属性切换) |
| NeoForge | 21.1.x+ |
| Java | 21 |
| Kotlin for Forge (KFF) | 5.x+ — 必装运行时依赖 |
gradle build
# 产物:build/libs/axo-platform-0.1.0.jar详见 BUILDING.md。
- 把
axo-platform-<version>.jar和 Kotlin for Forge 一起放进mods/ - 启动服务器,第一次会在
config/axoplatform.json写默认配置 - 编辑配置,填入
base_url与token,重启生效
config/axoplatform.json:
{
"base_url": "https://your-platform.example.com",
"token": "REPLACE_ME",
"poll_timeout_ms": 35000,
"connect_timeout_ms": 5000,
"request_timeout_ms": 10000,
"heartbeat_seconds": 30,
"leaderboard_seconds": 300,
"web_url": "",
"docs_dir": "docs",
"welcome_banner": true
}未填好 token 时不会启动 poll loop / 心跳,避免刷 401 日志;/axo web /axo docs 仍可用。
src/main/kotlin/net/axogc/neoforge/
├── PlatformMod.kt # @Mod 入口,生命周期/事件总线接线
├── commands/
│ ├── AxoCommand.kt # /axo Brigadier 根节点
│ ├── BindCommand.kt # /axo bind <CODE>
│ ├── WebCommand.kt # /axo web
│ └── DocsCommand.kt # /axo docs [path]
├── config/
│ └── PluginConfig.kt # JSON 配置加载(FMLPaths.CONFIGDIR)
├── handlers/
│ ├── CommandRouter.kt # /poll 下行命令分发
│ └── AdminCommandHandler.kt # admin.command.run(捕获 Brigadier 输出)
├── observation/
│ ├── PlayerListener.kt # 加入/离开 + 欢迎横幅
│ ├── ChatBridgeListener.kt # 游戏聊天上报
│ ├── HeartbeatTask.kt # 定时心跳
│ ├── LeaderboardTask.kt # 排行 snapshot 重建
│ └── LeaderboardSnapshot.kt # 原子切换的内存排行
├── stats/
│ └── StatsCollector.kt # 6 轴 metric + 读 stats/<uuid>.json
└── transport/
├── ApiClient.kt # HTTP 客户端(?token=)
├── Envelope.kt
├── Event.kt
└── PollLoop.kt
详见 PLAN §四。本模组与 paper-plugin 走完全相同的协议:
| 方向 | 端点 | 说明 |
|---|---|---|
| 下行(拉) | GET /api/srv/poll?token= |
长轮询 |
| 下行(回) | POST /api/srv/reply?token= |
回复需要响应的命令 |
| 上行 | POST /api/srv/heartbeat?token= |
心跳 + 在线人数 |
| 上行 | POST /api/srv/player.joined|left?token= |
玩家事件 |
| 上行 | POST /api/srv/chat.message?token= |
游戏内聊天 |
| 上行 | POST /api/srv/binding.request?token= |
绑定核验 |
| command | 说明 | 需要 reply |
|---|---|---|
player.kick |
踢出玩家 | 否 |
player.notify |
私聊通知 | 否 |
player.whitelist.add |
加白 | 是({added}) |
player.whitelist.remove |
移除白名单 | 是({removed}) |
player.stats.fetch |
按需查 stats | 是({stats}) |
metrics.list |
拉 metric 元数据 | 是({metrics}) |
leaderboard.fetch |
拉某 metric 排行 | 是({entries}) |
server.broadcast |
全服广播 | 否 |
chat.from_web |
回灌 web 聊天 | 否 |
admin.command.run |
管理员命令 | 是({ok, output, dispatched}) |
| 维度 | paper-plugin | neoforge-mod |
|---|---|---|
| 加载器 | Paper API(Bukkit superset) | NeoForge |
| Kotlin 运行时 | 直接打包进 jar | 依赖 KFF(运行时模组依赖) |
| 命令系统 | Bukkit CommandExecutor |
Brigadier |
| 事件订阅 | Listener + PluginManager.registerEvents |
@SubscribeEvent + NeoForge.EVENT_BUS.register |
| 任务调度 | Bukkit Scheduler | ScheduledExecutorService |
| Component | Adventure(net.kyori.adventure) |
Vanilla net.minecraft.network.chat.Component |
| 配置 | YAML(Bukkit FileConfiguration) | JSON(手写 + Gson) |
stats 读取、CommandRouter 分支、HTTP 协议、6 轴 metric、scales 数值都完全一致。