Skip to content

3.8.8.6

Latest

Choose a tag to compare

@MrPippi MrPippi released this 06 Jun 14:05

Changes

  • fix: replace jedis.keys() with cursor-based SCAN in clearUsersCheckedOutOnServer to 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 calls jedis.info("server") instead of the full INFO dump; add .trim() to strip CRLF from redis_version
  • fix: register pendingRequests cleanup via future.whenComplete() on the original future before orTimeout(), closing potential stale-entry leak
  • fix: replace INVENTORY_COMMAND with API as SaveCause for cross-server REQUEST_USER_DATA responses
  • fix: debug timestamp format mm:ss.SSSHH:mm:ss.SSS; replace per-call SimpleDateFormat + new Date() with static DateTimeFormatter + LocalTime.now()
  • fix: replace triple-lookup TOCTOU pattern in getPlayerCustomDataStore(OnlineUser) with computeIfAbsent
  • fix: split("/") called twice in CHECK_IN_PETITION handler
  • fix: add DataSyncer.syncAbortUserData(); LockstepDataSyncer overrides to conditionally release DATA_CHECKOUT (only if this server owns it) then unlock the player
  • fix: call syncAbortUserData() from handlePlayerQuit when player is still locked (join-sync in-flight), preventing orphaned DATA_CHECKOUT keys 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.