From 7613f4ecfbac5b219667713387e3d17fb58f02f4 Mon Sep 17 00:00:00 2001 From: laforetbrut Date: Thu, 26 Mar 2026 22:09:51 +0100 Subject: [PATCH] Fix backpack/shulker contents lost on transfer: never overwrite DB with empty data ROOT CAUSE: Sophisticated Backpacks/Storage wrappers cache inventory in memory. When store() reads from BackpackStorage/ItemContentsStorage, the SavedData may not have the latest wrapper state (unflushed changes). This returns empty/default NBT which overwrites the real data in our DB. Going back to the original server showed data because that server's local SavedData still had the correct data (never overwritten). FIX: saveStorageContents() now checks if the NBT is empty/minimal before writing. If the DB already has substantial data (>50 bytes) and the new NBT is empty, the save is SKIPPED to preserve the real data. This prevents the empty-overwrite scenario while still allowing legitimate saves of actual content. Vyrriox --- .../playersync/sync/addons/ModsSupport.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/vip/fubuki/playersync/sync/addons/ModsSupport.java b/src/main/java/vip/fubuki/playersync/sync/addons/ModsSupport.java index c6cd59c..cb16270 100644 --- a/src/main/java/vip/fubuki/playersync/sync/addons/ModsSupport.java +++ b/src/main/java/vip/fubuki/playersync/sync/addons/ModsSupport.java @@ -89,7 +89,28 @@ public class ModsSupport { * Generic method to save storage contents to DB for a given UUID. * Used for both Sophisticated Backpacks and Sophisticated Storage items. */ + /** + * Saves storage contents to DB, but ONLY if the NBT contains real data. + * If the NBT is empty/default (wrapper didn't flush to SavedData yet), + * we skip the save to avoid overwriting real data in the DB with empty content. + * This prevents data loss when the in-memory SavedData doesn't have the latest + * wrapper state (common with Sophisticated Backpacks/Storage). + */ private static void saveStorageContents(UUID contentsUuid, CompoundTag nbt) { + // Skip empty/minimal NBT to avoid overwriting real data in DB + if (nbt == null || nbt.isEmpty() || nbt.size() <= 1) { + // Check if DB already has data for this UUID - if so, don't overwrite with empty + try (JDBCsetUp.QueryResult qr = JDBCsetUp.executePreparedQuery( + "SELECT LENGTH(backpack_nbt) AS len FROM backpack_data WHERE uuid=?", contentsUuid.toString())) { + java.sql.ResultSet rs = qr.resultSet(); + if (rs.next() && rs.getInt("len") > 50) { + PlayerSync.LOGGER.debug("Skipping save of empty/minimal NBT for UUID {} - DB has {} bytes of real data", + contentsUuid, rs.getInt("len")); + return; + } + } catch (Exception ignored) {} + } + String serialized = VanillaSync.serializeTagToBinaryBase64(nbt); try { JDBCsetUp.executePreparedUpdate(