Revert "fallback BNBT, Compat with codec"

This reverts commit ce7004dba0.
This commit is contained in:
mlus 2026-02-24 10:24:13 +08:00
parent ce7004dba0
commit 148ac4db9b
3 changed files with 79 additions and 10 deletions

View File

@ -375,8 +375,34 @@ public class VanillaSync {
return ItemStack.EMPTY;
}
String nbtString = deserializeString(serializedNbt);
CompoundTag compoundTag = TagParser.parseTag(nbtString);
CompoundTag compoundTag;
String nbtString = serializedNbt; // Will be overwritten with decoded SNBT for legacy formats
// Try binary NBT format first (new format, avoids SNBT round-trip issues)
if (serializedNbt.startsWith("BNBT:")) {
try {
compoundTag = deserializeBinaryBase64Tag(serializedNbt);
} catch (Exception e) {
PlayerSync.LOGGER.error("Failed to deserialize binary NBT data, skipping item.", e);
return ItemStack.EMPTY;
}
} else {
// Legacy SNBT-based deserialization (B64: or old custom format)
nbtString = deserializeString(serializedNbt);
try {
compoundTag = TagParser.parseTag(nbtString);
} catch (CommandSyntaxException e) {
// TagParser may fail on certain 1.21.1 component SNBT formats (e.g. nested lists [[{...}]])
// Try NbtUtils.snbtToStructure as a fallback
PlayerSync.LOGGER.warn("TagParser.parseTag failed, trying NbtUtils.snbtToStructure fallback. SNBT: {}", nbtString);
try {
compoundTag = NbtUtils.snbtToStructure(nbtString);
} catch (CommandSyntaxException e2) {
PlayerSync.LOGGER.error("Both SNBT parsers failed for data: {}", nbtString);
throw e; // re-throw original exception
}
}
}
if (compoundTag.isEmpty() || !compoundTag.contains("id", Tag.TAG_STRING)) {
return ItemStack.EMPTY; // Invalid or empty tag
@ -578,11 +604,42 @@ public class VanillaSync {
// It's our placeholder, retrieve the original NBT string
return itemStack.getComponents().get(DataComponents.CUSTOM_DATA).copyTag().getString("playersync:original_item_nbt");
} else {
// It's a normal item or empty, serialize its current NBT
return serialize(serializeNBT(itemStack).toString());
// It's a normal item or empty, serialize using binary NBT to avoid SNBT round-trip issues
Tag tag = serializeNBT(itemStack);
if (tag instanceof CompoundTag compoundTag) {
return serializeTagToBinaryBase64(compoundTag);
}
// Fallback to SNBT-based serialization for non-compound tags
return serialize(tag.toString());
}
}
/**
* Serializes a CompoundTag to a Base64-encoded binary NBT string.
* This avoids SNBT round-trip issues where Tag.toString() produces SNBT
* that TagParser.parseTag() cannot parse back (e.g. with nested lists [[{...}]]).
*/
public static String serializeTagToBinaryBase64(CompoundTag tag) {
try {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
net.minecraft.nbt.NbtIo.writeCompressed(tag, baos);
return "BNBT:" + Base64.getEncoder().encodeToString(baos.toByteArray());
} catch (IOException e) {
PlayerSync.LOGGER.error("Failed to serialize NBT to binary, falling back to SNBT", e);
return serialize(tag.toString());
}
}
/**
* Deserializes a Base64-encoded binary NBT string back to a CompoundTag.
*/
public static CompoundTag deserializeBinaryBase64Tag(String encoded) throws IOException {
String base64 = encoded.substring(5); // Remove "BNBT:" prefix
byte[] bytes = Base64.getDecoder().decode(base64);
java.io.ByteArrayInputStream bais = new java.io.ByteArrayInputStream(bytes);
return net.minecraft.nbt.NbtIo.readCompressed(bais, net.minecraft.nbt.NbtAccounter.unlimitedHeap());
}
public static Tag serializeNBT(ItemStack itemStack) {
if (itemStack == null || itemStack.isEmpty()) {
return new CompoundTag();

View File

@ -42,8 +42,18 @@ public class ModsSupport {
ResultSet rsBackpack = qrBackpack.resultSet();
if (rsBackpack.next()) {
String serialized = rsBackpack.getString("backpack_nbt");
String nbtString = VanillaSync.deserializeString(serialized);
CompoundTag backpackNbt = TagParser.parseTag(nbtString);
CompoundTag backpackNbt;
if (serialized.startsWith("BNBT:")) {
backpackNbt = VanillaSync.deserializeBinaryBase64Tag(serialized);
} else {
String nbtString = VanillaSync.deserializeString(serialized);
try {
backpackNbt = TagParser.parseTag(nbtString);
} catch (CommandSyntaxException ex) {
PlayerSync.LOGGER.warn("TagParser.parseTag failed for backpack UUID {}, trying fallback", contentsUuid);
backpackNbt = net.minecraft.nbt.NbtUtils.snbtToStructure(nbtString);
}
}
// Update BackpackStorage with the retrieved NBT
net.p3pp3rf1y.sophisticatedbackpacks.backpack.BackpackStorage.get().setBackpackContents(contentsUuid, backpackNbt);
PlayerSync.LOGGER.info("Restored backpack data for UUID " + contentsUuid);
@ -54,6 +64,8 @@ public class ModsSupport {
PlayerSync.LOGGER.error("Error restoring backpack data for UUID " + contentsUuid, e);
} catch (CommandSyntaxException e) {
PlayerSync.LOGGER.error("Error parsing backpack NBT for UUID {}. Skipping backpack.", contentsUuid, e);
} catch (IOException e) {
PlayerSync.LOGGER.error("Error reading binary backpack NBT for UUID {}. Skipping backpack.", contentsUuid, e);
}
} else {
PlayerSync.LOGGER.warn("Backpack item in slot " + slot + " has no contentsUuid during restore");
@ -182,7 +194,7 @@ public class ModsSupport {
UUID contentsUuid = uuidOpt.get();
// Get internal backpack data from BackpackStorage (creates it if missing)
CompoundTag backpackNbt = net.p3pp3rf1y.sophisticatedbackpacks.backpack.BackpackStorage.get().getOrCreateBackpackContents(contentsUuid);
String serialized = VanillaSync.serialize(backpackNbt.toString());
String serialized = VanillaSync.serializeTagToBinaryBase64(backpackNbt);
try {
// Use REPLACE INTO so existing records are updated
JDBCsetUp.executeUpdate("REPLACE INTO backpack_data (uuid, backpack_nbt) VALUES ('" + contentsUuid + "', '" + serialized + "')");

View File

@ -46,8 +46,8 @@ public class LocalJsonUtil {
public static String cleanSnbt(String snbt) {
if (snbt == null) return null;
return snbt.replace("{\"\":", "{\"_\":")
.replace(",\"\":", ",\"_\":")
.replace("[\"\":", "[\"_\":");
return snbt.replaceAll(",\\s*\\{\"\":\"\"}", "")
.replaceAll("\\{\"\":\"\"}\\s*,", "")
.replaceAll("\\{\"\":\"\"}", "");
}
}