Folia 与 Luminol
目标版本
本页结论只针对 LotteryBox 1.0.4 当前源码与下表版本。升级 Folia、Luminol、Paper 或任一依赖后必须重新审查。
| 构建 | API/核心 | Java | 产物 |
|---|---|---|---|
| 1.21.11 | Folia 1.21.11 | Java 21 | LotteryBox-1.0.4-1.21.11.jar |
| 26.1.2 | Folia 26.1.2 stable build 8 | Java 25 | LotteryBox-1.0.4-26.1.2.jar |
| 26.2 | Luminol 26.2 build 726 stable | Java 25 | LotteryBox-1.0.4-26.2.jar |
folia-supported: true 只是一项加载声明,不证明线程安全、功能完整或第三方依赖兼容。
静态审查结果
| 规则 | 证据与结论 | 分类 |
|---|---|---|
| 启动检测 | onEnable 早期调用一次 SchedulerUtil.initialize(),结果缓存于静态字段;后续读取缓存 | 无硬规则命中 |
| 调度封装 | 业务调度集中进入 SchedulerUtil;Folia 路径直接调用官方 Entity、Region、Global、Async API,没有反射拼装调度 | 无硬规则命中 |
| 传统调度 | 定向扫描到的 Bukkit.getScheduler() 只在 SchedulerUtil 的非 Folia 分支 | 无硬规则命中 |
| 至少一 tick | 非拥有上下文的 Entity/Region 调度进入 runDelayed(..., 1);延迟参数用 Math.max(1, ticks);已经拥有目标上下文时直接执行,不发生跨 Region 调度 | 无硬规则命中 |
| Region 所有权 | Folia 使用 Bukkit.isOwnedByCurrentRegion(entity/location);Paper 分支才使用 Bukkit.isPrimaryThread() | 无硬规则命中 |
| 共享集合 | 付款 token、抽奖会话、编辑锁、复制状态、箱注册表、次数表和全息表使用 ConcurrentHashMap、并发 Set、快照或显式同步 | 尚未发现 must_fix;真实负载仍待运行时验证 |
| 传送 | 定向扫描未发现同步 teleport,当前业务也没有需要迁移到 teleportAsync 的传送操作 | 无硬规则命中 |
| 生命周期 | onDisable 注销监听器,取消午夜任务,关闭 metrics,并清理编辑、复制、购买、抽奖、全息状态,最后同步落盘 | 尚未发现 must_fix;异常终止不执行正常禁用流程 |
当前静态审查未发现需要在本次文档任务中标记为 must_fix 的 LotteryBox 硬规则违规。这个结论不是实时服务器证明;缺少目标生产服日志、压力负载、经济后端契约与故障注入结果的场景均属于 uncertain,不能补成“应该安全”。
五种不可用事件扫描
按当前 Folia 规则,以下事件在 Folia 层不可用,原因均为 Folia 层没有暴露可调用 API:
PlayerRespawnEventPlayerTeleportEventPlayerChangedWorldEventWorldLoadEventWorldUnloadEvent
本次对 src/main/java 的定向扫描没有发现任何类监听以上五种事件,因此没有可列出的命中类或监听器。若未来新增其中任一事件,必须重新报告具体类与监听器,不能假定它会工作,也不能在未收到明确需求时用未验证替代方案掩盖。
所有权与数据边界
实时 Player、Entity、World、Chunk、Block 与 Inventory 只能在所属 Entity/Region 上下文访问。跨边界流程应遵守:
- 在所有者上下文读取 UUID、名称、坐标副本、金额、货币 ID、奖品副本等快照;
- 有界异步任务处理经济或文件工作;
- 使用
runAtEntity或runAtRegion回到所有者上下文修改实时状态; - 在终止路径清理 token、任务、锁和引用。
Global 或 Async 上下文不能因为“能执行”就直接读写玩家背包或方块。Folia 下也不能用 Bukkit.isPrimaryThread() 判断目标 Region 所有权。
一 tick 边界
调用另一个 Entity/Region 的调度至少晚一 tick,这是 Folia 模型本身的约束。LotteryBox 当前封装的策略是:
- 已在目标所有者上下文:直接同步执行当前逻辑;
- 不拥有目标上下文:调度到目标并强制至少一 tick;
- Global:使用 GlobalRegionScheduler;
- 纯 I/O 或经济工作:使用 AsyncScheduler,但不碰实时状态。
不要通过反射、阻塞 Future 或跨 Region 锁绕过这一 tick,否则可能造成死锁、Region 饥饿或服务器崩溃。
运行时验证清单
静态审查不能替代真实 Folia/Luminol 测试。至少验证:
- 两名玩家在不同 Region 同时抽不同箱和同一箱;
- 快速连点、关闭 GUI、传送离开、退出服务器与背包满;
- DIRECT 扣款中改价、移除货币、切换模式或删除箱子;
- 经济后端超时、抛异常、扣款成功后退款失败;
- KEY 错箱、堆叠钥匙、动画启动失败和离线掉落;
/lb reload与正常停服后的任务、缓存、监听器和数据清理;- 升级核心后重新核对官方 API、事件可用性和所有权检查。
以上属于运行时验证边界;没有真实日志支持时,不应写成已经通过。