跳到主要内容

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 所有权

  • FoliaScheduleronEnable 早期初始化并缓存一次 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 会拒绝重载后的旧回调。

不可用事件扫描

针对当前两个服务端目标定向扫描了:

  • PlayerRespawnEvent
  • PlayerTeleportEvent
  • PlayerChangedWorldEvent
  • WorldLoadEvent
  • WorldUnloadEvent

Paper 插件源码没有发现这些事件的监听器,因此没有可列出的使用类或监听方法。目标核心升级后必须重新扫描。

仍需运行验证

真实服务器应覆盖:连接与握手、屏幕创建/删除、MPV/VLC、相机/360、资源重载、断线重连、插件关闭/重载、通过玩家跟踪发现世界,以及不同 Folia Region 的并发玩家。