Releases: MrPippi/HuskSync-26.1
Release list
3.8.8.6
Changes
- fix: replace
jedis.keys()with cursor-basedSCANinclearUsersCheckedOutOnServerto avoid O(N) blocking scan on startup/shutdown - fix: null-guard
jedis.get(key)in scan loop to prevent NPE on concurrent key deletion - fix:
getVersion()now callsjedis.info("server")instead of the full INFO dump; add.trim()to strip CRLF fromredis_version - fix: register
pendingRequestscleanup viafuture.whenComplete()on the original future beforeorTimeout(), closing potential stale-entry leak - fix: replace
INVENTORY_COMMANDwithAPIasSaveCausefor cross-serverREQUEST_USER_DATAresponses - fix: debug timestamp format
mm:ss.SSS→HH:mm:ss.SSS; replace per-callSimpleDateFormat+new Date()with staticDateTimeFormatter+LocalTime.now() - fix: replace triple-lookup TOCTOU pattern in
getPlayerCustomDataStore(OnlineUser)withcomputeIfAbsent - fix:
split("/")called twice inCHECK_IN_PETITIONhandler - fix: add
DataSyncer.syncAbortUserData();LockstepDataSynceroverrides to conditionally releaseDATA_CHECKOUT(only if this server owns it) then unlock the player - fix: call
syncAbortUserData()fromhandlePlayerQuitwhen player is still locked (join-sync in-flight), preventing orphanedDATA_CHECKOUTkeys and permanently stuck players on their next server
Fix Details
Orphaned DATA_CHECKOUT / player stuck in loading screen (critical)
When a player disconnected while their join-sync was still in-flight (isLocked=true at quit time), handlePlayerQuit silently skipped both the data save and the DATA_CHECKOUT key release. On reconnect to another server, that server would petition the original server to release checkout; the original server would ignore the petition because isLocked=true, leaving the player permanently stuck in the loading screen until a server restart.
Redis KEYS blocking scan
clearUsersCheckedOutOnServer() used jedis.keys(pattern), which blocks the entire Redis event loop for the duration of the scan. On large deployments this stalls the lockstep sync pipeline for all connected servers at every startup/shutdown. Replaced with cursor-based jedis.scan().
Concurrent-deletion NPE in KEYS loop
jedis.get(key).equals(serverName) threw NullPointerException when a peer server deleted the key between the KEYS result and the GET call. The Throwable catch absorbed the crash, silently skipping remaining checkout keys.
Debug timestamp wrong pattern
mm:ss.SSS uses minutes-of-hour for both fields, dropping hours entirely. Two events one hour apart produced identical timestamps. Pattern corrected to HH:mm:ss.SSS.
Based On
Upstream HuskSync — includes all fixes through 3.8.8 with additional Paper 26.1.2 support.
3.8.8.5
Changes
- feat: add
VERSION26_1 = 4786toDataVersionSupplierfor Paper 26.1.x
Fix Details
DataVersion mapping for Paper 26.1.x
DataVersionSupplier previously had no entry for the 26.1.x version line. Items deserialized on a 26.1.x server fell through to the default branch, which returned the last explicitly mapped version (1.21.11 = 4671). The correct data version for 26.1 is 4786. Without the correct mapping, NBTAPI's Data Fixer would migrate items from the wrong baseline, potentially corrupting enchantments, custom model data, and other item attributes.
Based On
Upstream HuskSync — includes all fixes through 3.8.8 with additional Paper 26.1.2 support.
3.8.8.4
Changes
- fix: use
plugin.runAsync()inrunTrackedAsync()instead of bareCompletableFuture.runAsync() - fix: log
ExecutionException(failed save) at WARNING level inawaitPendingSaves(); restore interrupt flag onInterruptedException - fix: remove redundant
pendingSaves.isEmpty()early return
Fix Details
ForkJoinPool / Folia compatibility
runTrackedAsync() previously submitted work to the bare JVM ForkJoinPool via CompletableFuture.runAsync(task). On shutdown, if awaitPendingSaves() timed out, those tasks could continue running after redisManager.terminate() closed the Jedis pool, causing JedisConnectionException that was silently swallowed — re-introducing the WiIIiam278#654 data-loss scenario. On Folia, the bare pool also lacked region context. The fix pre-creates a CompletableFuture and completes it inside the plugin.runAsync() lambda (MorePaperLib AsynchronousScheduler on Bukkit, ASYNC_EXEC on Fabric), ensuring tasks are bounded to the plugin lifecycle and Folia-safe.
Exception handling in awaitPendingSaves()
The previous catch (Exception ignored) silently discarded both ExecutionException (a player save failed mid-shutdown) and InterruptedException (interrupt flag lost). The fix logs a WARNING for failed saves and correctly restores Thread.currentThread().interrupt() on interruption.
Based On
Upstream HuskSync — includes all fixes through 3.8.8 with additional Paper 26.1.2 support.
3.8.8.3
Changes
- feat: add ASCII startup banner with unofficial fork notice on plugin load
- fix: move Redis connection termination out of
EventListenerinto platformonDisable()to ensure correct shutdown order
Fix Details
Redis shutdown order
In 3.8.8.2 the shutdown sequence called redisManager.terminate() inside EventListener.handlePluginDisable(), immediately after database.terminate(). Moving it to platform onDisable() (with a null guard) ensures Redis stays open until dataSyncer.terminate() has finished clearing checkout keys — then Redis closes last. This prevents a narrow window where another server could see a stale LATEST_SNAPSHOT key that was never cleaned up.
Startup banner
Adds an ASCII art banner and an unofficial-fork disclaimer box printed to the server log during onEnable(). No functional change.
Based On
Upstream HuskSync — includes all fixes through 3.8.8 with additional Paper 26.1.2 support.
3.8.8.2
Changes
- fix: prevent item duplication when dropping items before server shutdown (upstream #654)
- fix: gracefully handle per-data-type deserialization failures instead of crashing (upstream #584)
Fix Details
WiIIiam278#654 — Item duplication on shutdown
Paper fires PlayerQuitEvent (queueing an async save) before onDisable(). The async task raced against DB/Redis connection termination, failed silently, and left LATEST_SNAPSHOT stale — causing the destination server to restore the dropped item. The fix ensures all in-flight saves complete before connections are closed and checkout keys are cleared.
WiIIiam278#584 — NBT deserialization failure
When a player's stored NBT data is malformed or too large to parse, the plugin now gracefully skips the affected data type (logging a warning) instead of throwing an exception that prevented the player from loading their data at all.
Based On
Upstream HuskSync — includes all fixes through 3.8.8 with additional Paper 26.1.2 support.
3.8.8.1
HuskSync 3.8.8.1 (Paper 26.1.2 Fork)
This is an unofficial fork of WiIIiam278/HuskSync adding Paper 26.1.2 support and backporting upstream bug fixes.
Bug Fixes
- fix WiIIiam278#647 — Reduced
latest_snapshotRedis TTL from 1 year (~31M seconds) to 7 days, preventing Redis from accumulating tens of thousands of stale player keys over time - fix WiIIiam278#642 — Removed duplicate DataFixer item upgrade in
BukkitSerializer; NBTAPI 2.15.7 already applies DataFixerUtil internally viaDataVersiontag, so the manualupgradeItemStacks()call was causing double-migration of item NBT data - fix WiIIiam278#588 — Pre-filtered
Registry.MATERIALinto block-only and item-only sets (lazily cached), eliminating the N×M nested loop over all materials per statistic type that could cause CPU spikes to 100% on server startup
Supported Platforms
| JAR | Minecraft Version | Java |
|---|---|---|
HuskSync-Bukkit-3.8.8.1+mc.1.21.1.jar |
Paper 1.21.1 | 21 |
HuskSync-Bukkit-3.8.8.1+mc.1.21.4.jar |
Paper 1.21.4 | 21 |
HuskSync-Bukkit-3.8.8.1+mc.1.21.5.jar |
Paper 1.21.5 | 21 |
HuskSync-Bukkit-3.8.8.1+mc.1.21.8.jar |
Paper 1.21.8 | 21 |
HuskSync-Bukkit-3.8.8.1+mc.1.21.10.jar |
Paper 1.21.10 | 21 |
HuskSync-Bukkit-3.8.8.1+mc.1.21.11.jar |
Paper 1.21.11 | 21 |
HuskSync-Bukkit-3.8.8.1+mc.26.1.2.jar |
Paper 26.1.2 | 25 |
Paper 26.1.2 requires Java 25. All other versions require Java 21.
Based On
- Upstream: HuskSync 3.8.8
- item-nbt-api: 2.15.7 (fixes Paper 26.1.x version string format)
- triumph-gui: 3.1.13
HuskSync 3.8.8+mc26.1
HuskSync 3.8.8 adds support for Paper 26.1.2 (the new Minecraft versioning scheme).
What's new
- Paper 26.1.2 is now supported — Compatible with
26.1.2.build.53-stableand later 26.1.x builds - Updated NBT-API from 2.15.5 → 2.15.7, fixing a startup failure caused by Paper's new version string format (
26.x.x.build.xx-stable) - Updated Triumph-GUI from 3.1.12 → 3.1.13, adding improved support for 1.21.7+ inventory handling
Upgrading
To update from 3.8.7, drag and drop the correct jar for your server version. No config changes required.
Note: Paper 26.1.2 servers require Java 25. Ensure your server JVM is Java 25 or newer before upgrading.