From 15e45ac041b062cf2dfd2b8b0c96043a84f050f7 Mon Sep 17 00:00:00 2001 From: neko <68693406+nekotxs@users.noreply.github.com> Date: Sun, 2 Aug 2026 06:20:38 +0700 Subject: [PATCH 1/4] BaseMapCodec decode fix --- .../serialization/codecs/BaseMapCodec.java | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index 89835b64..13a71fdf 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -11,9 +11,10 @@ import com.mojang.serialization.Lifecycle; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; -import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; @@ -24,10 +25,41 @@ public interface BaseMapCodec { Codec elementCodec(); default DataResult> decode(final DynamicOps ops, final MapLike input) { - final Object2ObjectMap read = new Object2ObjectArrayMap<>(); + final List> pairs = input.entries().toList(); + + final ImmutableMap.Builder builder = ImmutableMap.builder(); + boolean anyDecodeFailure = false; + for (final Pair pair : pairs) { + final Optional k = keyCodec().parse(ops, pair.getFirst()).result(); + final Optional v = elementCodec().parse(ops, pair.getSecond()).result(); + if (k.isPresent() && v.isPresent()) { + builder.put(k.get(), v.get()); + } else { + anyDecodeFailure = true; + break; + } + } + + // failures and duplicates are rare, so it is okay to fall back to HashMap + // no failures: best performance + // failure: acceptable performance + if (!anyDecodeFailure) { + try { + return DataResult.success(builder.buildOrThrow()); + } catch (IllegalArgumentException duplicateKey) { + return fallbackDecode(ops, pairs); + } + } + + return fallbackDecode(ops, pairs); + } + + // HashMap fallback to check for failures and duplicates + private DataResult> fallbackDecode(final DynamicOps ops, final List> pairs) { + final Object2ObjectMap read = new Object2ObjectOpenHashMap<>(); final Stream.Builder> failed = Stream.builder(); - final DataResult result = input.entries().reduce( + final DataResult result = pairs.stream().reduce( DataResult.success(Unit.INSTANCE, Lifecycle.stable()), (r, pair) -> { final DataResult key = keyCodec().parse(ops, pair.getFirst()); From 63646b56a88b0bf24ea282a986e170ce4a3117c9 Mon Sep 17 00:00:00 2001 From: neko <68693406+nekotxs@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:28:32 +0700 Subject: [PATCH 2/4] replace hashmap with linked hashmap on fallback --- .../java/com/mojang/serialization/codecs/BaseMapCodec.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index 13a71fdf..b3b755f4 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -11,6 +11,7 @@ import com.mojang.serialization.Lifecycle; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -56,7 +57,7 @@ default DataResult> decode(final DynamicOps ops, final MapLike< // HashMap fallback to check for failures and duplicates private DataResult> fallbackDecode(final DynamicOps ops, final List> pairs) { - final Object2ObjectMap read = new Object2ObjectOpenHashMap<>(); + final Object2ObjectMap read = new Object2ObjectLinkedOpenHashMap<>(); final Stream.Builder> failed = Stream.builder(); final DataResult result = pairs.stream().reduce( From c33db6bfe2335ca5df6d48d889389143518d36ec Mon Sep 17 00:00:00 2001 From: neko <68693406+nekotxs@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:36:24 +0700 Subject: [PATCH 3/4] import clean --- src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index b3b755f4..161c17d6 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -13,7 +13,6 @@ import com.mojang.serialization.RecordBuilder; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.util.List; import java.util.Map; From bacc4168ac67449a901fdbcf28cb68475f644be6 Mon Sep 17 00:00:00 2001 From: neko <68693406+nekotxs@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:57:27 +0700 Subject: [PATCH 4/4] comment update --- src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java index 161c17d6..350ff9ce 100644 --- a/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java +++ b/src/main/java/com/mojang/serialization/codecs/BaseMapCodec.java @@ -40,7 +40,7 @@ default DataResult> decode(final DynamicOps ops, final MapLike< } } - // failures and duplicates are rare, so it is okay to fall back to HashMap + // failures and duplicates are rare, so it is okay to fall back to linked HashMap // no failures: best performance // failure: acceptable performance if (!anyDecodeFailure) {