Folia 与 Luminol 兼容性
状态定义
| 状态 | 含义 |
|---|---|
| 构建目标 | 能针对指定 Paper/Folia API 编译并生成 JAR |
| 静态审查 | 已检查调度、集合、生命周期、不可用事件和 Region 所有权 |
| 运行验证 | 已在明确服务端核心和构建号上完成真实服务器测试 |
静态审查不等于运行验收
folia-supported: true 只允许插件在 Folia 类服务端加载,不证明线程安全或功能完整。当前结论来自指定版本的源码审查、编译与单元测试,不是实际 Folia/Luminol 服务器验收;核心、Paper API 或下游分支升级后必须重新检查。
审查目标
- Luminol/Folia 1.21.11,编译 API 为 Paper 1.21.11。
- Canvas/Folia 26.2,编译 API 为 Paper 26.2 build 92。
- 客户端分别为 Minecraft 1.21.11/Java 21 和 26.2/Java 25。
Canvas 与编译使用的 Paper/Folia API 存在差异时,实际目标核心优先;没有对应核心源码或部署日志的行为标为 uncertain。
调度与 Region 所有权
FoliaScheduler在onEnable早期初始化并缓存一次 Folia 检测结果。- 业务代码不直接使用传统 BukkitScheduler;传统调度只存在于包装器的非 Folia 分支。
- Entity 和 Region 包装延迟被限制为至少 1 tick。
- Player、World 和 Location 的实时读取在 Player 实体所有者上下文执行。
- 跨上下文只传递 UUID、字符串、路径、字节数组、配置对象或不可变位置/权限快照。
- 不使用
Bukkit.isPrimaryThread()判断 Folia Region 所有权。
当前没有同步 teleport 调用,当前没有需要 teleportAsync 的传送操作。
并发、IO 与阻塞
- Player 版本跟踪使用并发集合,并在关闭或会话替换时取消超时任务。
DataHolder多张表由同一个锁保护,保留跨表原子性;不会在持锁状态等待关闭刷盘。- 文件和网络操作进入异步工作器,结果通过 Global 或 Entity 上下文写回。
- Region 回调不调用
Future.get()、CompletableFuture.join(),也不同步等待数据库、网络或文件 IO。 - 世界保存槽按活动维度合并,视频源解析并发受
VideoProviders.RESOLUTION_LIMIT限制。
生命周期与资源
以下资源具有显式终止路径:
- 玩家跟踪和重载握手任务。
- 世界保存防抖、重试和关闭刷盘任务。
- Residence 重试、缓存刷新和监听器。
- 原生运行库与
yt-dlp任务。 - 客户端外部 GL 纹理注册、相机 framebuffer 与渲染快照。
插件关闭时取消任务、注销监听器、停止执行器并清理玩家/世界/握手/持久化表;生命周期 epoch 会拒绝重载后的旧回调。
不可用事件扫描
针对当前两个服务端目标定向扫描了:
PlayerRespawnEventPlayerTeleportEventPlayerChangedWorldEventWorldLoadEventWorldUnloadEvent
Paper 插件源码没有发现这些事件的监听器,因此没有可列出的使用类或监听方法。目标核心升级后必须重新扫描。
仍需运行验证
真实服务器应覆盖:连接与握手、屏幕创建/删除、MPV/VLC、相机/360、资源重载、断线重连、插件关闭/重载、通过玩家跟踪发现世界,以及不同 Folia Region 的并发玩家。