UltiTools-API 6.3.0 Release Notes
6.3.0 consolidates the framework's command, configuration, transaction, module-lifecycle and panel integrations. These notes describe changes against the released v6.2.5 contents, not commit ancestry. The module EventBus and declarative GUI already existed in 6.2.5; the changes below repair and extend them rather than introduce them for the first time.
Before upgrading
- Back up the server configuration and module data. For JSON storage, back up
.ultitools-journaltogether with the tables; never delete that journal, and run only one server per data folder. - Install module builds compiled for UltiTools-API 6.3.0 with module
plugin.ymldeclaringapi-version: 630. If you rely on modules, stay on 6.2.5 until 6.3.0 builds of every module you use are published. Upgrading only the framework leaves the old modules unloaded. - Replace the framework and affected module JARs with the server stopped, then restart.
/ul reloadreloads configuration, not JARs. - The framework supports Paper 1.19.2 build 163 or newer, not plain Spigot. Use Java 17 below Paper 1.20.5, and Java 21 from Paper 1.20.5. Java 8 bytecode is not a Java 8 server-runtime promise.
- UltiKits, UltiLogin, UltiMail, UltiRemoteBag and UltiTrade require Paper 1.21 or newer; their inventory screens can fail on older supported framework servers (see known issues).
Module catalogue availability
At the 6.3.0 release, the /upm catalogue does not yet offer 6.3.0 (api-version: 630) module builds, and module builds made for 6.2.x are refused by 6.3.0 at startup. If your server relies on modules, stay on 6.2.5 until 6.3.0 builds of every module you use are available, then upgrade.
Breaking API changes and migration
Recompile downstream modules against 6.3.0 with the dependency kept provided (Maven) or compileOnly (Gradle). The upgrade checklist, removal registry and per-change record contain the full contracts and replacements. Notable changes include:
AbstractCommandExecutorand its misspelledAbstractCommendExecutorshim are removed. Extendabstracts.command.BaseCommandExecutorand implementhandleHelp(CommandSender).UltiToolsPlugin.unregisterSelf()andreloadSelf()are nowfinal. Move overrides toonUnregister()andonReload()and remove calls to the old superclass lifecycle methods. An old main class overriding either final method is refused withIncompatibleClassChangeError; modules with a hard dependency on it are also refused.- Removed types include
AbstractDataEntity(useBaseDataEntity<ID>),PagingPage(useBasePaginationPage),OkCancelPage(useBaseConfirmationPage),VersionWrapperandDefaultVersionWrapper(useXVersionUtils). - Removed registration APIs include the six-argument
UltiToolsPluginconstructor, the old seven-argumentPluginManager.register(...), package-based command/listener registration overloads, andListenerManager.register(UltiToolsPlugin, Listener). Use the current constructors and class-based/module-based registration APIs listed in the registry. TempListener.player(...)andPlayerTempListenerare removed; useTempListener.common(...)with a filter. The ineffective@OptionalParamannotation is removed without replacement.- The old CGLIB factory and proxy-creation APIs are removed; proxy construction uses ByteBuddy through
AopProxyResolver.Propagation.NESTEDis removed. UltiTools#getEconomy()is removed; useEconomyUtils.getEconomy()or its wrapper methods. The archived Adventure audience provider is removed; use Paper's native Adventure audiences.AbstractConfigEntity#getConfig()is removed. UseisPresentInFile(...)for presence checks, declared fields for values, and the explicit save APIs below.- The ineffective declarative GUI builder pairs
Container.background/getBackgroundandGridView.rows/getMaxRowsare removed.GuiRenderer.initializenow takes aSupplier<Widget>. - Per-viewer log-stream
start/stop/pause/resumeAPIs are removed rather than pretending to control delivery without browser identity; these remote actions are rejected.
There is no universal two-outcome rule for an old JAR: a class with an unavailable superclass can be skipped during scanning, an override of a newly final lifecycle method can refuse the module, and an old invocation of a removed method can fail only when executed with NoSuchMethodError. Consult the exact per-symbol record rather than treating successful startup as proof of compatibility.
Configuration and language files
- Operator-written configuration is not automatically repaired or overwritten. Invalid values are reported and refused (or use a declared default in memory where documented), not saved back as defaults. Unsupported or invalid constraints can refuse the affected module or reload.
- Configuration writes declare the keys they own and refuse a write if unrelated bytes cannot be preserved or the file changed since it was read. Read the warning, correct the named layout, or reload after an external edit, then retry. See the configuration chapter of
COMPATIBILITY.mdfor supported YAML layouts, atomic-write fallback and recovery limits. save()persists only module changes. Operator commands usesaveOperatorChange(...)orsaveOperatorMapEntry(...)for the named changes;OperatorFilescovers module-managed files. No configuration save happens automatically at shutdown, unload or replacement.ConfigConverter<T>with@ConfigConverterForis the new conversion extension point. Legacy parsers remain deprecated in 6.3.0 and are announced for removal in 6.4.0. Register converters for unsupported declared field types before configuration initialization.- Configuration-bound
@Scheduledand@CmdCDsupport live configuration values. Declareapi-version: 630, keep bound scheduled methods synchronous and remove the bound field's redundant@Range; the binding defines its accepted range. - To leave a text value blank, write
key: ''; deleting a key requests its default on next start. - Official language files are framework-owned and may be replaced on upgrade with a backup and log message. To customise text, copy a language file under a new name and select that copy; custom files remain operator-owned. Framework messages follow the selected
language.
Transactions, persistence and dependency injection
@Transactionalis wired through the AOP path for MySQL, SQLite and JSON. Rollback rules select the shallowest matching exception type;REQUIRES_NEWandNOT_SUPPORTEDsuspend the outer scope.- JSON transactions stage changes, publish atomically across a plugin's tables and recover through the journal after a crash. Durability and filesystem-specific limits are documented in JSON transactions. Ordinary writes and programmatic transaction reads can wait up to five seconds for table locks. For a read-modify-write in an annotated JSON transaction, use
updateIforREPEATABLE_READ. - A joined
@Transactionalmethod that throws an exception requiring rollback under its rollback rules, or a failing nestedDataOperator#transaction(...)scope, marks the whole transaction rollback-only even if its caller catches the exception. The outermost commit rolls back and throwsUnexpectedRollbackException. - JSON reads return detached copies; persist changes with
update(...). An unconditionaldel()is refused instead of deleting a whole table. Access to another module's entity operator is refused. - ByteBuddy replaces CGLIB. Detect proxies through
ProxyFactory.isProxyClass(...), not class names. Required injection failures and unproxyable required AOP contracts refuse module load. @Service(priority)resolves same-type candidates (higher wins); an exact tie is refused.registerSingletonapplies injection, lifecycle callbacks and bean post-processors.scanBasePackageClasses, composed stereotypes, the module's scan switches and conditional listener registration take effect. Missing dependencies and cycles refuse affected modules; a module JAR withoutname:is refused instead of sharing another module's storage.- Name-based class-loading filters are removed; they were not a sandbox. Module JAR validation retains the 100 MB size and 10,000-entry limits. Install only modules you trust.
Commands, tasks, GUI and module lifecycle
- Synchronous commands now run at dispatch on the primary thread, not one tick later. From an inventory click handler, defer inventory changes and command dispatch with
runTask. Nested command dispatch is immediate; a command dispatching itself meets its usage lock/cooldown on the same tick, and uncontrolled recursion can overflow the stack. Async bodies remain async. - Inherited
@CmdMappingand@Scheduledmethods are recognised.@CmdTargetuses override with narrowing; a widening or lateral override refuses the command class. Tab completion checks permission before contributing suggestions or invoking a suggestion method. - Cooldowns are scoped to executor instances;
@UsageLimitreleases acquired locks on refused dispatches as well as completed ones.ContainConsole()now defaults totrue.@AsyncCommand.timeout()stops waiting and reports the timeout; the body can continue in the background. - Declarative GUI state changes now repaint, grid placement supports general widget types, and clicks in the player's inventory no longer reach GUI-only handlers.
- Unload/reload lifecycle hooks retain framework cleanup;
getPluginList()returns an unmodifiable snapshot. Module replacement is observed at restart before the update is committed; an unsuccessful load can restore the retained previous JAR. - A failed
@PlayerCachesave does not stop other quit cleanup. The entry is still removed and the framework does not retry the save: modules needing stronger guarantees must persist/retry themselves.
UltiCloud and remote management
Immediate owner-authenticated /panel link cutover
Server-associated /panel magic-link creation requires the authenticated server owner immediately: there is no anonymous fallback and no grace period. Connect the server with /ulticloud login before requesting a link. This does not require every player opening the link to own the server. Ordinary website account login, browser magic-link verification and the in-game /login command remain unchanged.
UltiCloudRequests sends POST /auth/magic-link and GET /auth/magic-link/poll with the server credential. Poll by requestId, not player UUID; UUID-only polling is no longer supported. Handle NOT_CONNECTED without retrying anonymously, and call the helper off the primary thread. The authenticated request contract documents the helper API and failure handling.
Other remote changes
- Eight
ultipanel.capabilities.*switches gate panel operations. Monitoring, logs, player events and file reads default on; file writes, deletions, command execution and server-property access default off. Enable only the capabilities the operator wants. - Remote paths are resolved before use and constrained to editable roots; recursive deletion requires an explicit request. Deleting a symbolic link removes the link, not its target; recursive deletion does not follow links. Protected-file aliases are refused.
- The command blocklist is operator-editable. A malformed list is rejected as a whole with a warning and the defaults retained; an explicit empty list remains valid.
- Remote file refusals are recorded as
DENIEDin the remote action log. Server-property edits and other file writes use their respective capability switches. - Cloud login/logout, token refresh and WebSocket work are scoped to one session: retired work cannot reactivate a logged-out session. Credentials move to the server's
.ultikitscredential store. If an old and a malformed current store coexist, neither identity is overwritten; correct the current document before retrying. - The framework's log stream mirrors console output on Paper 1.20.5 and newer. On Paper 1.19.2 to 1.20.4 the console mirror is unavailable: startup warns and the stream carries plugin lines only. Neither case fixes the panel browser's live-connection defects listed below.
Known issues and workarounds
These limitations are tracked for 6.4.0. Module and panel entries are ecosystem limitations, not claims that this framework release repairs those separately delivered products.
| Affected product / symptom | What to do meanwhile | Tracking |
|---|---|---|
Framework: /upm check can say no updates during the first seconds of startup | Wait for the console's startup update-check result, then retry. | #663 |
| Framework: a module requiring Paper 1.21 or newer can, on older Paper, be misreported as built against an older framework | Check the module's server requirement before blaming its framework build. | #658 |
| UltiKits, UltiLogin, UltiMail, UltiRemoteBag and UltiTrade inventory screens can fail on older Paper | Run these five modules on Paper 1.21 or newer. | #655 |
| Framework: a partial module reload repeats its result twice in the log and once in the reply | Read the first result; ignore the duplicates. | #665 |
| Framework: reload/config wording may imply a restart or mix languages; YAML-anchor comments may expand after a language change | Correct the named invalid value and run /ul reload; the refused panel edit wrote nothing and needs no restart. | #598 |
| UltiEconomy: a process stop between debit and credit can lose a transfer without a log entry | No module workaround; after an unclean stop, check reported missing transfers and correct balances manually. | #44 |
| UltiEconomy: transfer/refund failure replies can be misleading; a note redemption without a balance row can give no reply and retain the note | After a database problem, inspect balances and logs before paying again. | #45 |
UltiLogin: console/panel logadmin reset can expose the new password in logs | Reset passwords in game, where logging is masked, and keep logs private. | #57 |
| UltiWorlds: failed PvP persistence can leave the live flag changed until the next player enters that world | Repeat the command and confirm the live and saved values agree. | #58 |
| Panel: plugin configuration editor is blank/unavailable | Edit configuration files directly on the server. | Tracked internally |
| Panel: Settings says saved before the server accepts; some of its 14 settings do not exist on every server | Check the actual server setting; do not treat the success message as confirmation. | Tracked internally |
| Panel: no browser live push, no remote command output, and the management status strip says Disconnected even when online | Read output in the server console and use the dashboard for online state. | Tracked internally |
| Panel: a refused command still reports Command execution request sent | Check ultipanel.capabilities.commands and the server console; commands default off. | Tracked internally |
| Panel: legacy paid activation-code redemption for permanent Pro is unavailable or fails | No verified self-service workaround. Eligible holders' historical permanent Pro entitlement remains supported; the complete repair is deferred to 6.4.0 and redemption may remain unavailable until then. | Tracked internally |
Developer CLI: ultikits versions list prints undefined fields | Look up module versions in the panel or catalogue web page. | Tracked internally |
Further reference
- COMPATIBILITY.md: migration checklist, configuration write rules, support matrix, transaction durability limits and runtime dependency ownership.
- compatibility/records/6.3.0.md: exact removals and runtime changes.
- compatibility/DEPRECATIONS.md: cumulative generated registry.
- XSeries is no longer shaded into the framework; modules using it declare it themselves as
provided/compileOnly. Paper loads the framework's declared libraries and supplies Gson, MySQL Connector/J, protobuf and slf4j. The framework's build uses JDK 21 with Java 8 bytecode; it does not establish a separate runtime floor for dependencies supplied by Paper.
Ling Bao