UltiTools-API 6.5.0 更新说明
6.5.0 加强了面板远程命令检查,修复了 UltiCloud 回复和玩家链接投递,并允许在未改变的 YAML 块标量后追加缺失的配置默认键。本次还改进了模块错误报告和链接诊断,校验玩家缓存保存声明,并弃用但不删除旧的语言声明。
面向模块作者的完整清单见 COMPATIBILITY.md,发布页见 GitHub 上的 v6.5.0。
远程命令默认值变化
默认 ultipanel.commands.blocklist 新增 execute、return 和 function。已有列表不会自动追加或改写;如需相同的拦截,请自行添加。停服、编辑列表后重新启动:/ul reload 不会重读此列表。
重点:远程命令边界与回复可靠性
- 默认黑名单从十项增加到十三项。新安装和缺少此键的配置会拒绝直接执行
execute、return和function,也拒绝minecraft:execute等带命名空间的形式。远程命令仍由ultipanel.capabilities.commands: false默认关闭。(#912) - 在服务器线程即将执行命令时,检查按 Bukkit 的命令名、标签和别名进行双向匹配,忽略大小写和命名空间。列入
plugins会同时拦截pl、bukkit:pl,列入pl也会拦截plugins。同步嵌套进入BaseCommandExecutor的调用会在帮助、校验器和命令体之前再次检查。(#905) - 确认接收请求后,若未包装的
Error从命令分发中逸出,现在会返回command_failed,不再让面板收不到结果。LinkageError被处理后不再抛出,其他错误则在回复后继续传播。在 Paper 1.21.11 上,原始 Bukkit 命令失败会被包装成CommandException,6.4.0 就已返回command_failed;未包装错误的路径由仓库单元测试构件覆盖。反射调用的框架命令体失败仍作为普通命令输出返回。(#905) - 异步玩家传送的回复等待上限为 25 秒。超时返回
internal_error和teleport did not complete in time,但不会取消传送;重试前请检查玩家实际位置。晚到的完成通知不会产生第二个回复。(#905)
升级前准备
- 支持的服务器仍为 Paper 1.19.2 build 163 至 Paper 1.21.x,Spigot 不是受支持的目标。6.4.0 更新说明中的旧版 Paper 模块要求仍然适用。
- 手工检查已有远程命令黑名单。若要允许三个新增的默认命令,请在停服时只删除对应条目,再重新启动。空列表(
[])会关闭可配置黑名单,但不会取消对面板发起的 UltiCloud 登录和登出的独立拒绝。 - 检查每个
@PlayerCache(saveBeforeRemove = true)Bean:具体 Bean 必须实现PlayerCacheSaver,继承的字段也适用。否则注册现在会抛出PluginModuleException。请实现savePlayerData(UUID);不需要保存时,改为saveBeforeRemove = false。(#897) - 检查查询条件中的 null 和非有限数字。SQLite、MySQL 和 JSON 的
getAll、exist、page及条件删除现在会一致拒绝这些值。updateIf保留已记录的EQUAL配 null 语义(IS NULL),但拒绝其他 null 比较和非有限条件值。 - 用打包进 JAR 的
lang/<code>.json、.yml或.yaml资源替换旧语言声明。@I18n和@UltiToolsModule(i18n = ...)在 6.5.0 中仍可编译和加载;缺少打包资源时会新增警告。
新增
ErrorReportCollector#reportErrorFromClass(Throwable, Class<?>, TriggerContext)根据具体类的 JAR 解析错误所属模块。已有reportError入口仍然保留。ErrorReportCollector标记为@ApiStatus.Internal,这些入口不供模块代码使用。(#900)
修复
- 未改变的字面量(
|)或折叠(>)YAML 块标量后跟空行时,现在可以追加缺失的配置默认键。块标量的原始写法、缩进指示、chomping 标记、指示行注释和尾部空行保持逐字节不变,也保留一致的 LF、CRLF 或 CR 换行。此项修复了 6.4.0 列出的默认键插入限制。(#895) - SQLite、MySQL 和 JSON 现在以
DataAccessException和DATA_ENTITY_INVALID拒绝 null 或无穷大/NaN 条件值,不再因后端不同而得到空结果、意外匹配或原始异常。JSON 的del(WhereCondition.empty())也会抛出该类型异常;所有后端对没有 ID 的实体调用exist(entity)都返回 false。上文说明的updateIf例外保持不变。(#873) - 玩家链接创建回复丢失时,暂存的完成事件占用会在连接关闭或报错后释放,以便无需重启即可重投。回执检查与占用是原子的;暂存的完成或过期事件会等创建 future 的回调返回后再投递。调用方取消 future 不再阻止传输层清理。(#905)
- 命令和
@ExceptionCatch错误按具体执行器或 Bean 类所属的 JAR 归属到已加载模块,代理 Bean 也适用。来源缺失、无法匹配或匹配不唯一时,仍不标记模块。去重、采样和合并按模块隔离,两个模块的同形异常不再合为一组。identify-string 缺失或无效时,回退到规范化的plugin.yml名称。(#900) - 错误文本遵守网关的 UTF-16 长度上限,且不会拆开代理对;日志时间戳被限制在协议范围内,避免单个无效时间戳使整批日志被拒绝。(#900)
- REST 设备登录的
Retry-After接受 1–86400 秒,且不会把过期处理推迟到设备码截止时间之后。支持协议的响应头使用约定的 1–99 范围;登录冷却剩余秒数向上取整,不再在冷却尚未结束时显示零秒。不存在或不是目录的可编辑根路径不再出现在远程文件列表中。(#886) - 遥测快照只在监控发布新样本后重建;被拒绝且内容不变的负载不再每秒重试。缓冲日志文本在内存中设有上限,凭据文件中的整数在保存后仍保持整数。(#886)
- 链接审计的字段引用采用
Owner.name:descriptor格式。离线--own接受点分或斜杠分隔的包根,并按包边界匹配;退出码区分自身代码问题(1)、参数错误(2)、API 路径不存在或模块 JAR 无法读取(3)。跳过类的汇总会在正常日志级别显示原因,没有丢失处理器时不再提示隔离处理器。哪些类和 Bean 能加载没有变化。(#892)
变更
plugin.yml的libraries:现在请求net.bytebuddy:byte-buddy:1.18.17(原为1.18.15),由 Paper 在首次启动时下载;预先填充libraries/的离线服务器须包含新版本。(#894)- 模块能力版本只读取版本核心部分:
2.0-rc1和2.0+build.9都声明为2.0.0,不再从后缀提取数字。(#905) - 构建与工具:二进制兼容性基线改为 6.4.0;离线运行时 API 测试构件检查新增显式跳过选项,并修正构建辅助程序和发布资产检查。本次包含依赖、CI 和测试隔离维护,不改变框架最低服务器要求。(#893、#896)
已知限制
- 远程命令黑名单不是沙箱。检查覆盖外层命令和同步嵌套的框架执行器,不覆盖经包装命令、
commands.yml、数据包函数、第三方转派器或后续 tick 到达的全部原版/Bukkit 目标。除非自行加入schedule,否则schedule function <pack>:x …仍被允许。必须禁用这些路径时,请保持ultipanel.capabilities.commands: false,不要向不可信的操作员开放远程命令。 - 别名匹配依据 Bukkit 元数据,不会传递遍历别名关系,也不覆盖原版 Brigadier 重定向。需要时请逐项列出各个拼写。只有包装命令保留面板 sender 时,嵌套拒绝才会进入面板结果;若改用控制台或玩家 sender,拒绝就发送到对应位置。
- 命令回复不是秘密脱敏边界。未登记的参数及第三方异常文本可能出现在本地记录或回复中;不要在命令回复里打印其他用户的秘密。
- 在玩家链接处理器注册前收到的过期事件仍会被消费。请先注册处理器,再创建链接。已经运行的处理器在重连期间仍保持执行中。
- 若需要改变块标量本身的值或分隔行、输入无效、包含锚点/别名,或其他布局无法保留,仍会拒绝追加 YAML 默认键。文件保持不变,请手工添加缺失键。6.4.0 中独立的单文件崩溃安全 YAML 限制继续适用。
PlayerCacheSaver保存失败时仍会警告并删除缓存条目。注册检查不提供重试或持久化保证;关服时也不会通过此 hook 保存仍在线的玩家。- 文件/配置、云端客户端和关闭窗口的其余限制见 COMPATIBILITY.md。
弃用
@I18n 和 @UltiToolsModule(i18n = ...) 自 6.5.0 起弃用并标记待删除,并未移除。按既有政策,它们最早可能在 6.6.0 删除。自 6.3.0 起,支持语言来自模块自身 JAR 内的资源,而不是这些声明。请删除旧声明并打包语言文件。(#901、#915)
获准加载的模块声明了语言却未在 JAR 内打包对应资源时,会输出一条列出全部缺失代码的警告。两种声明会合并、排序并去重;资源齐全或声明为空时不额外警告。磁盘文件和 supported() 覆盖不能满足此资源检查,但语言选择及已有覆盖行为不变。
已删除的 API
6.5.0 删除了以下八个数据访问成员;它们在 6.4.0 中已弃用,并预告于 6.5.0 删除:
DataStore#checkOwnership(File, Class)DataStore#checkOwnership(UltiToolsPlugin, Class)JsonStore#getOperator(UltiToolsPlugin, Class)JsonStore#getOperator(File, Class)MysqlDataStore#getOperator(UltiToolsPlugin, Class)MysqlDataStore#getOperator(File, Class)SQLiteDataStore#getOperator(UltiToolsPlugin, Class)SQLiteDataStore#getOperator(File, Class)
请迁移到 DataStore#getOperator(DataScope, Class);普通模块应使用 UltiToolsPlugin#getDataOperator(Class)。第三方调用方必须更新源码并重新编译。已发布的 UltiKits 模块均未使用这些成员。
破坏性变更
上述八个数据访问 API 的删除对第三方调用方不保持二进制兼容。本次还包含以下行为兼容性变化:
- 新配置或缺少该键的配置默认禁止远程执行
execute、return和function。已有列表不变;已注册别名和同步嵌套框架命令会接受更严格的检查。 - 要求保存玩家缓存但未实现保存接口时,现在会拒绝注册,不再静默删除条目而不保存。
- 无效查询条件值在各后端统一以类型化异常拒绝。依赖空结果、原始异常或意外匹配的代码需要调整;
updateIf的EQUAL配 null 契约保留。
这些属于行为变化,不是删除 @I18n 或它的模块别名。从 6.3.x 升级时,仍须完成 6.4.0 的 API 删除迁移。