Corrupt shop loading was destructive and crashed. Both branches of the
debug.delete-corrupt-shops check called deleteShop, so a shop whose
container was temporarily missing lost its signs and its database row
even with the option disabled. deleteShop then refunded through a null
economy core and threw, aborting shop loading and ChunkLoadEvent.
- ContainerShop#handleLoading now unloads instead of deleting when
delete-corrupt-shops is false, leaving the row and signs intact.
- SimpleEconomyTransaction fails transactions with a lastError instead
of dereferencing a null core in checkBalance, commit and
failSafeCommit.
- SimpleShopManager#refundShop skips and warns when no economy is
loaded, matching the guards every other economy call site has.
- The economy bridge loads before shops instead of one tick after, so
refunds during loading can see it. EconomyLoader#load is now
idempotent and the post-startup attempt reports a missing bridge at
WARN rather than only at debug level.
Adventure was compiled against 4.22.0 while Purpur 1.19.4 provides
4.13.1 at runtime, so any 4.14+ call would have been a
NoSuchMethodError. Pin the API to 4.13.1, align the platform artifacts
to 4.3.2 in both the build and plugin.yml, and drop the ANSI and JSON
serializers, which do not exist at 4.13.1 and were only used to print
classpaths in diagnostics.
Also:
- Add /qs beacon, which marks empty shops with particle columns that are
only sent to the command runner.
- Add ShopManager#transferShopsOwnership so ShopBridge-OG can move shops
to a new owner when an AreaShop-OG plot is transferred.
- Keep SubstAgent $ENV_VAR placeholders on disk. Bukkit reads configs
through FileInputStream, which SubstAgent intercepts, so saving the
config persisted resolved credentials. The config file is now only
rewritten when a migration actually changed something, and every save
restores the raw tokens read back through NIO.
- Use SubstAgent's $VAR syntax for the database credentials. The ^{VAR}
form was never substituted, since SubstAgent only triggers on '$'.
- Read the configuration once instead of in both onLoad and onEnable.
- Name the log sink that logging.location selects instead of always
claiming qs.log.
- Warn when an item expression references an unregistered item, which
previously produced a rule that silently never matched.
- Stop shipping example rules as live config, and tolerate an empty
limits.ranks section instead of throwing.
- Default debug.disable-debuglogger to false and legacy-updater
shop-sign to false.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>