From 606fe47b574e0dc30b1daccde7448bd8daa8a9f3 Mon Sep 17 00:00:00 2001 From: N-Echelibe Date: Tue, 4 Aug 2026 20:11:57 +0100 Subject: [PATCH] fix(storage): resolve NBT/JSON serialization failure for server item components - Prefer `connection.registryAccess()` over `level.registryAccess()` in `Storage` to match multiplayer network registries. - Wrap `DataComponentPatch.CODEC` with `SAFE_COMPONENT_PATCH_CODEC` in `ModCodecs` to catch unresolvable registry errors (e.g., server enchantments/trims) and fall back to empty component patches instead of failing the entire memory bank file save. Fixes issue #22 --- .../chesttracker/impl/storage/Storage.java | 10 ++++++-- .../chesttracker/impl/util/ModCodecs.java | 23 ++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/client/java/red/jackf/chesttracker/impl/storage/Storage.java b/src/client/java/red/jackf/chesttracker/impl/storage/Storage.java index 6d0bf7fe..c77eba42 100644 --- a/src/client/java/red/jackf/chesttracker/impl/storage/Storage.java +++ b/src/client/java/red/jackf/chesttracker/impl/storage/Storage.java @@ -74,9 +74,12 @@ public static Optional load(String id) { return existing; var level = Minecraft.getInstance().level; + var connection = Minecraft.getInstance().getConnection(); HolderLookup.Provider registries = null; - if (level != null) { + if (connection != null) { + registries = connection.registryAccess(); + } else if (level != null) { registries = level.registryAccess(); } @@ -94,9 +97,12 @@ public static void save(MemoryBankImpl bank) { } var level = Minecraft.getInstance().level; + var connection = Minecraft.getInstance().getConnection(); HolderLookup.Provider registries = null; - if (level != null) { + if (connection != null) { + registries = connection.registryAccess(); + } else if (level != null) { registries = level.registryAccess(); } diff --git a/src/client/java/red/jackf/chesttracker/impl/util/ModCodecs.java b/src/client/java/red/jackf/chesttracker/impl/util/ModCodecs.java index 95e1966d..b6ad1725 100644 --- a/src/client/java/red/jackf/chesttracker/impl/util/ModCodecs.java +++ b/src/client/java/red/jackf/chesttracker/impl/util/ModCodecs.java @@ -26,6 +26,27 @@ * Codecs for classes that aren't ours */ public class ModCodecs { + private static final Codec SAFE_COMPONENT_PATCH_CODEC = new Codec<>() { + @Override + public DataResult> decode(DynamicOps ops, T input) { + DataResult> res = DataComponentPatch.CODEC.decode(ops, input); + if (res.isError()) { + return DataResult.success(Pair.of(DataComponentPatch.EMPTY, input)); + } + return res; + } + + @Override + public DataResult encode(DataComponentPatch input, DynamicOps ops, T prefix) { + DataResult res = DataComponentPatch.CODEC.encode(input, ops, prefix); + if (res.isError()) { + FileUtil.LOGGER.warn("Failed to encode item DataComponentPatch ({}); falling back to empty patch for item", res.error().get().message()); + return DataComponentPatch.CODEC.encode(DataComponentPatch.EMPTY, ops, prefix); + } + return res; + } + }; + /** * Identical to {@link ItemStack#OPTIONAL_CODEC}, but will not enforce a max stack size of 99. */ @@ -35,7 +56,7 @@ public class ModCodecs { // Item.CODEC.fieldOf("id").forGetter(ItemStack::getItem), Item.CODEC.fieldOf("id").forGetter(stack -> BuiltInRegistries.ITEM.wrapAsHolder(stack.getItem())), ExtraCodecs.POSITIVE_INT.fieldOf("count").orElse(1).forGetter(ItemStack::getCount), - DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(ItemStack::getComponentsPatch) + SAFE_COMPONENT_PATCH_CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(ItemStack::getComponentsPatch) ).apply(instance, (Holder itemHolder, Integer count, DataComponentPatch patch) -> { ItemStack stack = new ItemStack(itemHolder, count); stack.applyComponents(patch);