UltiTools-API 6.3.0 更新说明
6.3.0 整合了框架的命令、配置、事务、模块生命周期和面板集成。 本说明以已发布的 v6.2.5 内容为比较基准,而不是提交之间的祖先关系。 模块 EventBus 和声明式 GUI 在 6.2.5 中已经存在; 下文介绍的是对它们的修复和扩展,并非首次引入。
升级前准备
- 备份服务器配置和模块数据。使用 JSON 存储时,将
.ultitools-journal与数据表一起备份;不要删除该日志目录,每个数据目录只允许一个服务器使用。 - 安装针对 UltiTools-API 6.3.0 编译的模块构建,并在模块
plugin.yml中声明api-version: 630。如果服务器依赖模块,请继续使用 6.2.5,直到所用的每个模块都发布了 6.3.0 构建。只升级框架会导致旧模块无法加载。 - 停服后替换框架和受影响模块的 JAR,再重启服务器。
/ul reload只重载配置,不会重载 JAR。 - 框架支持 Paper 1.19.2 build 163 或更新版本,不支持普通 Spigot。 Paper 1.20.5 之前使用 Java 17,从 Paper 1.20.5 起使用 Java 21。Java 8 字节码不代表承诺支持 Java 8 服务器运行时。
- UltiKits、UltiLogin、UltiMail、UltiRemoteBag 和 UltiTrade 要求 Paper 1.21 或更新版本; 在框架支持的较旧服务器上,它们的物品栏界面可能失败(见已知问题)。
模块目录可用性
6.3.0 发布时,/upm 目录尚未提供 6.3.0(api-version: 630)模块构建, 6.3.0 也会在启动时拒绝为 6.2.x 构建的模块。如果服务器依赖模块, 请继续使用 6.2.5,等所用的每个模块都有 6.3.0 构建后再升级。
不兼容的 API 变更与迁移
使用 6.3.0 重新编译下游模块,并将依赖保持为 provided(Maven)或 compileOnly(Gradle)。完整契约和替代方案见升级检查清单、 移除登记表和 逐项变更记录。 主要变更如下:
- 移除了
AbstractCommandExecutor及其拼写错误的兼容类AbstractCommendExecutor。 请继承abstracts.command.BaseCommandExecutor并实现handleHelp(CommandSender)。 UltiToolsPlugin.unregisterSelf()和reloadSelf()现在为final。将覆写逻辑移至onUnregister()和onReload(),并移除对旧父类生命周期方法的调用。 覆写任一 final 方法的旧主类会因IncompatibleClassChangeError被拒绝加载; 硬依赖该模块的模块也会被拒绝加载。- 移除的类型包括
AbstractDataEntity(改用BaseDataEntity<ID>)、PagingPage(改用BasePaginationPage)、OkCancelPage(改用BaseConfirmationPage)、VersionWrapper和DefaultVersionWrapper(改用XVersionUtils)。 - 移除的注册 API 包括六参数的
UltiToolsPlugin构造器、旧的 七参数PluginManager.register(...)、按包注册命令或监听器的 重载,以及ListenerManager.register(UltiToolsPlugin, Listener)。请使用登记表中列出的现行构造器 及基于类或模块的注册 API。 - 移除了
TempListener.player(...)和PlayerTempListener;改用带过滤条件的TempListener.common(...)。 无实际作用的@OptionalParam注解已移除,没有替代项。 - 移除了旧 CGLIB 工厂和代理创建 API;代理现在通过
AopProxyResolver使用 ByteBuddy 构建。 移除了Propagation.NESTED。 - 移除了
UltiTools#getEconomy();改用EconomyUtils.getEconomy()或其包装方法。 已归档的 Adventure audience provider 也已移除;请使用 Paper 原生 Adventure audiences。 - 移除了
AbstractConfigEntity#getConfig()。检查键是否存在时使用isPresentInFile(...), 读取值时使用声明的字段,保存时使用下文列出的显式保存 API。 - 移除了声明式 GUI 中无实际作用的 builder 方法对
Container.background/getBackground和GridView.rows/getMaxRows。GuiRenderer.initialize现在接受Supplier<Widget>。 - 移除了按查看者控制日志流的
start/stop/pause/resumeAPI, 不再在缺少浏览器身份的情况下假装控制投递;这些远程操作会被拒绝。
旧 JAR 的结果并不能统一归为两类:父类不可用的类可能在扫描时被跳过, 覆写新设为 final 的生命周期方法可能导致整个模块被拒绝加载, 调用已移除方法的旧代码则可能直到实际执行时才以 NoSuchMethodError 失败。 请查阅具体符号的变更记录,不要将启动成功视为兼容性证明。
配置与语言文件
- 不会自动修复或覆盖服主编写的配置。无效值会被报告并拒绝使用 (在已说明的情形下使用声明的默认值作为内存值),不会将默认值写回文件。 不支持或无效的约束可能导致受影响模块或重载被拒绝。
- 配置写入会声明自己负责的键;如果无法保留无关字节,或文件在读取后发生变化, 则拒绝写入。请阅读警告,修正指出的布局问题,或在外部编辑后先重载,再重试。 支持的 YAML 布局、原子写入的回退方式和恢复限制见
COMPATIBILITY.md的配置章节。 save()只持久化模块自身的更改。服主命令使用saveOperatorChange(...)或saveOperatorMapEntry(...)保存指定的更改;模块管理的文件使用OperatorFiles。 关闭、卸载或替换时都不会自动保存配置。ConfigConverter<T>与@ConfigConverterFor是新的转换扩展点。 旧解析器在 6.3.0 中仍为弃用状态,计划于 6.4.0 移除。 对于尚不支持的声明字段类型,请在配置初始化之前注册转换器。- 绑定配置的
@Scheduled和@CmdCD支持实时配置值。请声明api-version: 630,保持绑定的定时方法同步执行,并移除绑定字段上 多余的@Range;可接受的范围由绑定定义。 - 要将文本值留空,请写
key: '';删除键会在下次启动时请求使用默认值。 - 官方语言文件由框架管理,升级时可能被替换,同时保留备份并记录日志。 如需自定义文本,请复制语言文件并使用新名称,再选择该副本; 自定义文件仍由服主管理。框架消息遵循所选的
language。
事务、持久化与依赖注入
@Transactional已通过 AOP 路径接入 MySQL、SQLite 和 JSON。 回滚规则选择匹配深度最浅的异常类型;REQUIRES_NEW和NOT_SUPPORTED会挂起外层作用域。- JSON 事务暂存更改,在一个插件的各张表之间原子发布,并在崩溃后通过日志恢复。 持久性和文件系统相关限制见 JSON 事务。 普通写入和编程式事务读取可能为等待表锁阻塞最多五秒。 在注解式 JSON 事务内进行读后修改再写入时,请使用
updateIf或REPEATABLE_READ。 - 已加入现有事务的
@Transactional方法抛出按其回滚规则需要回滚的异常, 或嵌套的DataOperator#transaction(...)作用域失败时,即使调用者捕获异常, 也会将整个事务标为 rollback-only。最外层提交会回滚并抛出UnexpectedRollbackException。 - JSON 读取返回独立副本;修改后使用
update(...)持久化。 无条件del()会被拒绝,而不是删除整张表。访问其他模块的实体操作器也会被拒绝。 - ByteBuddy 替代了 CGLIB。请通过
ProxyFactory.isProxyClass(...)检测代理,不要依赖类名。 必需的注入失败或必需的 AOP 契约无法代理时,模块会被拒绝加载。 @Service(priority)用于选择同类型候选(数值较高者优先);最高优先级相同则拒绝。registerSingleton会执行注入、生命周期回调和 bean 后处理器。scanBasePackageClasses、组合构造型注解、模块的扫描开关和条件监听器注册均已生效。 依赖缺失或循环依赖会导致受影响模块被拒绝加载; 缺少name:的模块 JAR 会被拒绝,不再与其他模块共用存储。- 移除了基于名称的类加载过滤器;它们不是沙箱。 模块 JAR 校验保留 100 MB 大小和 10,000 个条目的限制。请只安装你信任的模块。
命令、任务、GUI 与模块生命周期
- 同步命令现在派发时就在主线程上执行,不再等到下一个 tick。 在物品栏点击处理器中,请使用
runTask延后物品栏更改和命令派发。 嵌套命令派发立即执行;命令派发自身时,会在同一个 tick 遇到自己的使用锁或冷却, 不受控的递归可能导致栈溢出。异步方法体仍然异步执行。 - 继承的
@CmdMapping和@Scheduled方法会被识别。@CmdTarget采用允许缩小范围的覆盖语义; 扩大或横向改变范围的覆写会导致命令类被拒绝。Tab 补全在提供建议或调用建议方法之前检查权限。 - 冷却以执行器实例为作用域;
@UsageLimit在派发被拒绝和执行完成时都会释放已取得的锁。ContainConsole()现在默认为true。@AsyncCommand.timeout()会停止等待并报告超时;方法体可能继续在后台运行。 - 声明式 GUI 的状态变化现在会触发重绘,网格布局支持通用组件类型, 玩家自身物品栏中的点击不再传递给仅面向 GUI 的处理器。
- 卸载和重载生命周期钩子会保留框架清理逻辑;
getPluginList()返回不可修改的快照。 模块替换会在重启时观察加载结果,然后才提交更新; 加载失败时可以恢复保留的旧 JAR。 @PlayerCache保存失败不会中断玩家退出时的其他清理。缓存条目仍会被移除, 框架不会重试保存;需要更强保证的模块必须自行持久化或重试。
UltiCloud 与远程管理
/panel 链接立即切换为服主认证
创建与服务器关联的 /panel magic-link 立即要求已认证的服务器所有者身份: 没有匿名回退,也没有宽限期。请求链接前,请先通过 /ulticloud login 连接服务器。 这不要求每个打开链接的玩家都拥有该服务器。 普通网站账号登录、浏览器 magic-link 验证和游戏内 /login 命令保持不变。
UltiCloudRequests 使用服务器凭据发送 POST /auth/magic-link 和 GET /auth/magic-link/poll。 轮询时使用 requestId,不要使用玩家 UUID;不再支持仅凭 UUID 轮询。 遇到 NOT_CONNECTED 时不要匿名重试,并在主线程之外调用该辅助类。 认证请求契约说明了辅助 API 和失败处理方式。
其他远程管理变更
- 八个
ultipanel.capabilities.*开关控制面板操作。监控、日志、玩家事件和文件读取默认开启; 文件写入、删除、命令执行和服务器属性访问默认关闭。 请只启用服主需要的能力。 - 远程路径在使用前会被解析,并限制在可编辑的根目录内;递归删除需要显式请求。 删除符号链接只会移除链接,不会删除目标;递归删除不会跟随链接。 受保护文件的别名会被拒绝访问。
- 命令黑名单可由服主编辑。格式错误的列表会被整体拒绝, 同时记录警告并保留默认值;显式空列表仍然有效。
- 远程文件操作被拒绝时,会在远程操作日志中记录为
DENIED。 服务器属性编辑和其他文件写入分别使用各自的能力开关。 - 云登录、登出、令牌刷新和 WebSocket 工作都限定在单个会话内: 已失效的工作不能重新激活已登出的会话。凭据迁移到服务器的
.ultikits凭据存储。 如果旧存储与格式错误的当前存储同时存在,两者的身份都不会被覆盖; 请先修正当前文档,再重试。 - 在 Paper 1.20.5 及更新版本上,框架日志流会镜像控制台输出。 在 Paper 1.19.2 至 1.20.4 上无法镜像控制台:启动时会警告,日志流只包含插件日志行。 两种情况都没有修复下表列出的面板浏览器实时连接缺陷。
已知问题与临时处理方式
这些限制计划在 6.4.0 跟进。模块和面板条目属于生态产品的限制, 并不表示本次框架发布修复了这些独立交付的产品。
| 受影响产品 / 症状 | 临时处理方式 | 跟踪 |
|---|---|---|
框架:/upm check 在启动后的最初几秒可能提示没有更新 | 等待控制台输出启动更新检查结果,再重试。 | #663 |
| 框架:要求 Paper 1.21 或更新版本的模块,在较旧 Paper 上可能被误报为针对旧框架构建 | 先检查模块的服务器版本要求,再判断是否为框架构建问题。 | #658 |
| UltiKits、UltiLogin、UltiMail、UltiRemoteBag 和 UltiTrade 的物品栏界面在较旧 Paper 上可能失败 | 请在 Paper 1.21 或更新版本上运行这五个模块。 | #655 |
| 框架:部分模块重载时,结果会在日志中重复两次,在回复中重复一次 | 读取第一次结果,忽略重复内容。 | #665 |
| 框架:重载或配置提示可能让人误以为需要重启,或混用语言;切换语言后 YAML 锚点注释可能展开 | 修正指出的无效值后运行 /ul reload;被拒绝的面板编辑没有写入任何内容,无需重启。 | #598 |
| UltiEconomy:扣款和入账之间进程停止,可能导致转账丢失且没有日志记录 | 没有模块层面的临时处理方式;非正常停服后,请核查报告的丢失转账并手动修正余额。 | #44 |
| UltiEconomy:转账或退款失败的回复可能误导;没有余额行时兑换纸币可能没有回复,并保留纸币 | 数据库出问题后,再次付款前先检查余额和日志。 | #45 |
UltiLogin:控制台或面板执行 logadmin reset 可能在日志中暴露新密码 | 在游戏内重置密码,该路径会遮蔽密码日志,并保持日志私密。 | #57 |
| UltiWorlds:PvP 持久化失败后,运行时标志可能维持已更改状态,直到下一个玩家进入该世界 | 重新执行命令,确认运行时值与保存值一致。 | #58 |
| 面板:插件配置编辑器为空或不可用 | 直接在服务器上编辑配置文件。 | Tracked internally |
| 面板:设置页在服务器接受前就提示已保存;其中 14 项设置有些并非每个服务器都具备 | 检查服务器的实际设置,不要将成功消息当作确认。 | Tracked internally |
| 面板:浏览器没有实时推送、没有远程命令输出,管理状态栏即使在线也显示 Disconnected | 在服务器控制台读取输出,使用仪表盘确认在线状态。 | Tracked internally |
| 面板:命令被拒绝后仍提示 Command execution request sent | 检查 ultipanel.capabilities.commands 和服务器控制台;命令默认关闭。 | Tracked internally |
| 面板:旧付费激活码兑换永久 Pro 不可用或失败 | 没有已验证的自助临时处理方式。符合条件的持有者原有的永久 Pro 权益仍受支持;完整修复延后至 6.4.0,此前兑换可能持续不可用。 | Tracked internally |
开发者 CLI:ultikits versions list 的字段显示为 undefined | 在面板或目录网页中查询模块版本。 | Tracked internally |
延伸参考
- COMPATIBILITY.md:迁移检查清单、配置写入规则、支持 矩阵、事务持久性限制和运行时依赖归属。
- compatibility/records/6.3.0.md:精确的移除项和运行时变更。
- compatibility/DEPRECATIONS.md:累计生成的登记表。
- XSeries 不再打包进框架;使用它的模块需自行声明为
provided/compileOnly。Paper 加载框架声明的库,并提供 Gson、 MySQL Connector/J、protobuf 和 slf4j。框架使用 JDK 21 构建,输出 Java 8 字节码; 这并不为 Paper 提供的依赖另行设定运行时最低版本。
Ling Bao