Skip to content

UltiTools-API 6.4.0 Release Notes ​

6.4.0 lets modules compiled against current Paper run on older supported Paper versions. The framework adapts the server API calls a module makes while the module loads, and it adds a start-up report of the references it cannot adapt. 6.4.0 also adds config-bound async scheduling and an opt-in crash-safe YAML writer, and it collects the 6.3.2 follow-up fixes.

The full list for module authors is in COMPATIBILITY.md. The release itself is v6.4.0 on GitHub.

Five modules need 6.4.0 below Minecraft 1.21

UltiLogin, UltiMail, UltiKits, UltiRemoteBag and UltiTrade were compiled against Paper 1.21 and fail on older servers with UltiTools 6.3.x. On Paper 1.19.2 build 163 to 1.20.x they need UltiTools 6.4.0 or later and the module versions listed below. On Paper 1.21 and later, UltiTools 6.3.x keeps working.

Headline: modules for current Paper on older servers ​

  • Load-time adaptation. When a module class loads, the framework changes call shapes that differ between the server the module was compiled for and the server it runs on. The first case is a server API type that is a class on one version and an interface on another, such as InventoryView, which raised IncompatibleClassChangeError on older servers. The owner, member name and descriptor of each call stay the same. Module JAR files on disk are never modified.
  • What it does not do. The framework does not supply APIs that an older server lacks, rename events, or isolate handlers inside a class. There is no operator switch to turn the adaptation off.
  • Start-up report. Each module logs one INFO summary of how many classes and call sites were adapted, including zero.
  • Linkage audit. After the main class loads and before components are scanned, the framework logs one WARNING for each reference in the module's own scanned packages that the server cannot resolve and that no adaptation covers. Each WARNING names the module, the class and the method. References in bundled third-party libraries produce one INFO line per top-level library package. When a bean is skipped because a server class is missing, the log names the module, the bean, the missing class and every affected event handler, including inherited ones.
  • Offline audit command. The same audit can run against a module JAR before it is deployed, with repeatable --own package roots. Only findings in the module's own packages give a non-zero exit code.

Which modules need what ​

ModuleNeeds UltiTools-API 6.4.0 below Minecraft 1.21Notes
UltiLoginYes: UltiLogin 2.1.0 (released)On Minecraft 1.21 or later it needs UltiTools-API 6.3.1 or later. On a Paper version without an event one of its login protections uses, the mount guard falls back to the older mount event, and the item-pick, sign-opening and equipment-slot-swap guards are each skipped with one console warning; the other protections stay registered. Changes: UltiLogin#85, #86.
UltiMailYes: UltiMail 2.1.0 (released)On Minecraft 1.21 or later it keeps working on UltiTools-API 6.3.0 or later. Changes: UltiMail#67.
UltiKitsYes: UltiKits 2.1.0 (released)On Minecraft 1.21 or later it keeps working on UltiTools-API 6.3.0 or later. Changes: UltiKits#58.
UltiRemoteBagYes: UltiRemoteBag 2.1.0 (released)On Minecraft 1.21 or later nothing changes (UltiTools-API 6.3.0 or later). Changes: UltiRemoteBag#80.
UltiTradeYes: UltiTrade 2.1.0 (released)On Minecraft 1.21 or later it keeps working on UltiTools-API 6.3.0 or later. On Minecraft 1.19.2–1.19.3 the title of an already-open trade window does not refresh. Changes: UltiTrade#92, #93.

The five module versions above add a start-up check. On Minecraft below 1.21 with UltiTools older than 6.4.0, the module refuses to start with an English and Chinese message that asks you to update UltiTools. UltiTools 6.3.x on Minecraft 1.21 or later is unaffected. A 6.4.0-SNAPSHOT counts as 6.4.0. If a version string cannot be read, the module warns and continues. All five module versions were released before UltiTools-API 6.4.0 and are available from their GitHub releases (linked above) and in the UltiCloud catalogue. Module releases are separate from this release; each module's release notes list its other changes.

Before upgrading ​

  • Supported servers: Paper 1.19.2 build 163 or later up to Paper 1.21.x. Spigot is not a supported target.
  • UltiLogin: upgrade to 2.1.0 before upgrading UltiTools-API to 6.4.0. UltiLogin 2.1.0 works on UltiTools-API 6.3.1 or later. UltiLogin 2.0.0's /panel references SimpleHttpClient and UltiCloudRequests, which 6.4.0 removes, so /panel fails on 6.4.0 (its /login is unaffected). There is no bridge for 2.0.0.
  • Servers below Minecraft 1.21: update UltiTools-API to 6.4.0, then the module versions above.
  • Offline-owner trade cancellation (UltiTrade 2.1.0): if a cancelled trade cannot find its owner online, the owner's stake is saved and delivered at their next join. If saving fails and no real owner location exists, the items go to the original initiator and are never dropped at world spawn. Every redirect is logged with owner, recipient and items.
  • Custom async scheduling or YAML writing: read the two new features below before adopting them.

Added ​

  • Async config-bound @Scheduled tasks. async = true is now accepted on a task whose timing is bound to a config key. The trigger still runs on the main thread and only the method body runs on an async worker, one tick after the trigger. /ul reload keeps the trigger's phase. Slow bodies may overlap, as with literal async tasks, and async code must not use thread-unsafe Bukkit APIs. Existing annotation signatures and sync or literal-async behavior do not change. (#535, #797)
  • CrashSafeYamlFiles. An opt-in API for a module's explicit create or edit of an operator YAML file. A reader sees either the old file or the complete new file, never a partly written one. It requires an ordinary file on a local POSIX filesystem, keeps permission bits, owner and group, and refuses a file that changed since it was read. No module is migrated automatically and normal configuration loading is unchanged. See COMPATIBILITY.md for platform limits. (#545, #798)
  • Sensitive remote-console commands hidden in local records. When the panel's remote console runs a command that a module registered as sensitive (for example UltiLogin's logadmin), its arguments are shown as *** in the [Remote command] echo line, the blocked line, the refusal record and the action-log target; a failure line shows only the command name. The command is still dispatched with its arguments and its reply is unchanged; unregistered commands are logged as received. This deliberately changes local log content compared with 6.3.1 and 6.3.2. See COMPATIBILITY.md, "Sensitive commands in the remote console's local records". (#868)

Fixed ​

  • Config warnings for a map key that contains an escaped line break stay on one log line. Warnings for refused named configuration migrations now say why the insertion would change how the server reads that key. (#851)
  • The start-up log capture is released when onLoad fails. (#858)
  • A failed update check now reports that failure, a simple-name clash across modules is reported once, and the undeclared-key warning is capped. (#855)
  • The staged-read reason key in the Chinese language file uses Chinese source text. (#854)
  • Unused SQLite pool settings were removed. (#850)
  • The release tooling names the repository in every gh call and finishes drafts as requested. (#864)

Changed ​

  • The binary-compatibility check now compares against 6.3.2. (#860)
  • A CI job audits the framework's linkage against pinned Paper API 1.19.2 and 1.20.6 graphs. (#846)
  • UAT-CHECKLIST.md rows are written against the build's API level. (#856)

Known limitations ​

  • Diagnostics are not recovery. If a bean is skipped because a server class is missing, its event handlers are lost. Move optional handlers outside every scanBasePackages prefix, check that the class exists, then register them explicitly. The older-servers guide describes the pattern.
  • A class that extends or implements an API whose kind changed, or that uses an affected special invocation, is refused instead of partly adapted.
  • The per-reference WARNING applies to the module's own component-scan packages. A shaded library relocated into a scan package still gives one WARNING per reference. Before the 6.3.2 scanner fix, a scan root also matched sibling packages that share its text prefix, so give optional-handler packages a name that does not start with any scan root.
  • The INFO counts are a start-up snapshot, not a prediction for classes loaded later.
  • Crash-safe YAML covers a single file only. Multi-file crash transactions are not provided. Leftover staging files after a hard crash need a manual look. Non-POSIX filesystems and files with Java-visible ACLs are refused.
  • Bodies of async config-bound tasks that are already running may finish after the module unloads.
  • A new default key is not appended after a block scalar followed by a blank line (#883). When an operator-edited YAML file has a block scalar (|-) followed by a blank line, the framework does not append a newly introduced default key. The file is left unchanged, the default applies in memory, and a WARN names the key; add the key by hand. This is the same behavior as 6.3.2, not a 6.4.0 regression.
  • The remaining 6.3.x known limitations (remote files, the cloud client, panel re-attach) are listed in COMPATIBILITY.md.

Deprecated ​

Eight methods that were never deprecated before are deprecated in 6.4.0 with @Deprecated(since = "6.4.0", forRemoval = true). They are scheduled for removal in 6.5.0, the first release the one-MINOR removal rule allows. Their behavior is unchanged. (#880)

  • DataStore#checkOwnership(File, Class)
  • DataStore#checkOwnership(UltiToolsPlugin, Class)
  • JsonStore#getOperator(UltiToolsPlugin, Class) and JsonStore#getOperator(File, Class)
  • MysqlDataStore#getOperator(UltiToolsPlugin, Class) and MysqlDataStore#getOperator(File, Class)
  • SQLiteDataStore#getOperator(UltiToolsPlugin, Class) and SQLiteDataStore#getOperator(File, Class)

Replacement: DataStore#getOperator(DataScope, Class). A module calls UltiToolsPlugin#getDataOperator(Class).

Breaking changes ​

6.4.0 removes the 72 public API entries that 6.3.0 and 6.3.1 announced for removal in 6.4.0. Each carried @Deprecated(forRemoval = true) and @removeIn 6.4.0 in a released version, so a module that still used one was warned by name at compile time. A module compiled against 6.3.x that calls a removed member fails with NoSuchMethodError or NoClassDefFoundError on 6.4.0. Recompile against 6.4.0 and apply the migration in the "Removal list for 6.4.0" section of COMPATIBILITY.md. (#880)

Protocol v1 WebSocket and panel path (48 entries). The pre-2.1.0 UltiCloud path is gone. The framework's own UltiCloud session (protocol 2.1.0) already carries every panel request, so a server operator sees no change.

  • Data and client types: ApiResponse, TokenEntity, ServerEntityVO, UltiPanelWebSocketClient, ReconnectStrategy, ExponentialBackoffStrategy and its Builder (7).
  • The v1 entry points, handlers and listeners of the internal managers CommandExecutionManager (3, with CommandResult), FileOperationManager (2), ServerPropertiesManager (2), LogStreamManager (9), PlayerEventManager (8) and ServerMonitorManager (9), plus the UltiPanelLogTransmitter(UltiPanelWebSocketClient, String) constructor (1). CommandExecutionManager#execute(String, String, Executor, CommandResultSink) replaces executeCommand(JsonObject); the others have no replacement.
  • Login and token helpers (7): CloudAuthManager#login(Runnable, Consumer, Runnable, Consumer, Consumer) (use login(DeviceLoginListener)), CloudAuthManager.CloudStatus#getUserName() and #getExpirationDate() (use getServerName() or getServerId()), HttpRequestUtils#registerServer, #updateServer and #getServerByUUID, and PluginInitiationUtils#startTokenRefreshScheduler().

Legacy config parsers (6 entries). @ConfigEntry(parser = ...), Parser, ObjectConfigSerializer, ConfigParser, DefaultConfigParser and StringHashMapParser. Delete parser = ... and register a ConfigConverter<T> annotated @ConfigConverterFor(T.class) in a scanned package. DefaultConfigParser and StringHashMapParser declarations are simply deleted, because the built-in conversions cover those types. See "Migrating legacy parsers to converters" in COMPATIBILITY.md.

HTTP clients (7 entries). SimpleHttpClient with Response (use HttpURLConnection or your own HTTP client), and UltiCloudRequests with get, post, Outcome and Result (use CloudPlayerLinks, available from UltiTools#getCloudPlayerLinks()).

Other (11 entries).

  • DataStore#getOperator(UltiToolsPlugin, Class) and #getOperator(File, Class) (2): use UltiToolsPlugin#getDataOperator(Class). A custom store overrides getOperatorUnchecked(DataScope, Class).
  • TransactionManager#getConnection(), #setIsolationLevel(int) and #setReadOnly(boolean) (3): program against JdbcTransactionManager.
  • The four short SimpleTempListener constructors (4): use TempListener.common(Class) or the four-argument constructor.
  • PluginDependencyResolver.PluginNode#getAllDependencies(Set) (1): use getAllDependencies(Set, Map).
  • AnnotationUtils#findAnnotation(Class, Class) (1): use MergedAnnotationResolver.find(Class, Class).

Behavior notes:

  • UltiToolsPlugin#getDataOperator and UltiToolsAPI.getDataOperator no longer fall back to the removed overloads when no DataScope was set. They refuse with ENTITY_NOT_OWNED. Normal module loading always sets the scope.
  • TransactionInterceptor and TransactionAwareDataSource dispatch on JdbcTransactionManager or JsonTransactionManager. Any other manager gets the same UnsupportedOperationException the removed defaults threw.
  • UltiPanelLogTransmitter's batch, replay and interval setters are now no-ops or only store their value.

Binary-compatibility check: the japicmp baseline stays at the released 6.3.2. Each removed symbol is named by its own <exclude> entry (no package-wide exclusion), and the deprecation registry (compatibility/DEPRECATIONS.md) marks all 72 entries REMOVED in 6.4.0, so no entry remains announced for 6.4.0. One internal class, LegacyParserAdapter, has an exclude of its own, for 73 named excludes in total. On the 6.4.0 version-finalization build, japicmp 0.26.5 comparing 6.4.0 with 6.3.2 classifies the change as semver MINOR and reports no binary-incompatible change outside those named excludes. The new 6.4.0 deprecations are not japicmp changes.

Contributors

The avatar of contributor named as Claude Opus 5.5 Claude Opus 5.5
The avatar of contributor named as Ling Bao Ling Bao
The avatar of contributor named as a a

Released under the MIT License.