单元测试全绿,一上真服直接崩:Shadow minimize 的闷棍
2026 年 9 月 9 日到 11 日(Commit 7a26070),我立项开发了专为 Folia 打造的传送集合插件 igng-dev/IGNGTeleport,把大家每天都要用的 Home(家)、Warp(地标)、TPA/TPAHere(玩家互传)以及主世界/下界/末地三维度安全随机传送(RTP)收拢到了一个插件里。
结果第一次打包丢进真服做冒烟测试,就给了我一记响亮的闷棍:本地编译和单元测试明明全绿,可插件一进服启动直接报错崩溃!排查后发现踩了两个大坑:一是 Gradle 的 Shadow 打包插件开启了 minimize(),因为 MySQL JDBC 驱动是通过字符串反射加载的,没有静态代码引用,打包时直接被当作“无用代码”偷偷裁掉了;二是 JDBC 连接参数里把字符集写成了 MySQL 内部名 utf8mb4,驱动根本不认。我赶紧给驱动包加上了裁剪豁免、在构建期塞入独立类加载器自检测试,才把这关过了。
区块边缘(X=15)往外多看一格引发的血案
上线跑起来后,9 月 16 日(v1.0.1,Commit f1e0139)又在实战中抓出了两个深水区 Bug。
第一个是 Folia 特有的跨区异常:RTP 在检查落点安全性时,会顺便检查脚下和四周一格的方块。当随机坐标刚好落在区块边缘(比如区块内局部坐标 X=15 或 Z=15)时,往旁边多看一格就会跨进隔壁区块;如果隔壁区块刚好划归另一个 Folia 线程区域管辖甚至还没加载,当场就会抛出 AsyncChunkLoadException!我把安全检查严格收敛在当前已异步加载的单个区块边界内,彻底消灭了这个隐患。同时还砍掉了在只有 4 个连接的 HikariCP 池子里混用 MySQL GET_LOCK 存家导致的连接耗尽死锁。
预热 20 个安全落点 + 坏区黑名单:敲完 /rtp 50 毫秒秒传
以前玩家敲 /rtp 随机传送,最烦的就是要在原地傻等好几秒甚至十几秒,因为服务器正在后台疯狂随机抽坐标、异步加载区块、发现是茫茫大海或者岩浆海又得推倒重抽。
到了 9 月 26 日发布的 v1.1.0(Commit aa7e898),我加上了两大杀手锏:**后台落点预生成缓存池(RtpLocationCache)**和 LRU 空间坏区记忆(RtpSpatialMemory)。插件在服务器空闲时就悄悄在后台预热攒好 20 个已经验证安全的落点坐标,遇到大片海洋或下界岩浆海的网格直接记入 LRU 坏区黑名单跳过磁盘 IO;当玩家敲下 /rtp 的那一刻,直接从缓存池里弹出一个现成坐标送过去,耗时从十几秒直接降到了 0~2 tick(50 毫秒以内)秒传!顺手还给 TPA 请求配上了直观的 [接受] [拒绝] [拒绝并拉黑] 聊天栏三按钮和漂亮的彩虹渐变标题。