diff --git a/build.gradle b/build.gradle index 09eecedb1..bec7d283f 100644 --- a/build.gradle +++ b/build.gradle @@ -949,6 +949,7 @@ project(':forge') { exclude 'net/minecraftforge/fml/common/versioning/InvalidVersionSpecificationException.java' exclude 'net/minecraftforge/fml/common/versioning/Restriction.java' exclude 'net/minecraftforge/fml/common/versioning/VersionRange.java' + exclude 'net/minecraftforge/common/LenientUnboundedMapCodec.java' tasks { main { diff --git a/patches/minecraft/net/minecraft/util/registry/SimpleRegistry.java.patch b/patches/minecraft/net/minecraft/util/registry/SimpleRegistry.java.patch new file mode 100644 index 000000000..b7405af28 --- /dev/null +++ b/patches/minecraft/net/minecraft/util/registry/SimpleRegistry.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/util/registry/SimpleRegistry.java ++++ b/net/minecraft/util/registry/SimpleRegistry.java +@@ -212,7 +212,8 @@ + } + + public static Codec> func_241745_c_(RegistryKey> p_241745_0_, Lifecycle p_241745_1_, Codec p_241745_2_) { +- return Codec.unboundedMap(ResourceLocation.field_240908_a_.xmap(RegistryKey.func_240902_a_(p_241745_0_), RegistryKey::func_240901_a_), p_241745_2_).xmap((p_239656_2_) -> { ++ // FORGE: Fix MC-197860 ++ return new net.minecraftforge.common.LenientUnboundedMapCodec<>(ResourceLocation.field_240908_a_.xmap(RegistryKey.func_240902_a_(p_241745_0_), RegistryKey::func_240901_a_), p_241745_2_).xmap((p_239656_2_) -> { + SimpleRegistry simpleregistry = new SimpleRegistry<>(p_241745_0_, p_241745_1_); + p_239656_2_.forEach((p_239653_2_, p_239653_3_) -> { + simpleregistry.func_218381_a(p_239653_2_, p_239653_3_, p_241745_1_); diff --git a/src/main/java/net/minecraftforge/common/LenientUnboundedMapCodec.java b/src/main/java/net/minecraftforge/common/LenientUnboundedMapCodec.java new file mode 100644 index 000000000..e62089825 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/LenientUnboundedMapCodec.java @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +package net.minecraftforge.common; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; +import com.mojang.datafixers.util.Unit; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; +import com.mojang.serialization.MapLike; +import com.mojang.serialization.codecs.BaseMapCodec; + +import java.util.Map; +import java.util.Objects; + +/** + * Key and value decoded independently, unknown set of keys + */ +public class LenientUnboundedMapCodec implements BaseMapCodec, Codec> +{ + private final Codec keyCodec; + private final Codec elementCodec; + + public LenientUnboundedMapCodec(final Codec keyCodec, final Codec elementCodec) { + this.keyCodec = keyCodec; + this.elementCodec = elementCodec; + } + + @Override + public Codec keyCodec() { + return keyCodec; + } + + @Override + public Codec elementCodec() { + return elementCodec; + } + + @Override // FORGE: Modified from decode() in BaseMapCodec + public DataResult> decode(DynamicOps ops, MapLike input) + { + final ImmutableMap.Builder read = ImmutableMap.builder(); + final ImmutableList.Builder> failed = ImmutableList.builder(); + + final DataResult result = input.entries().reduce( + DataResult.success(Unit.INSTANCE, Lifecycle.stable()), + (r, pair) -> { + final DataResult k = keyCodec().parse(ops, pair.getFirst()); + final DataResult v = elementCodec().parse(ops, pair.getSecond()); + + final DataResult> entry = k.apply2stable(Pair::of, v); + entry.error().ifPresent(e -> failed.add(pair)); + entry.result().ifPresent(e -> read.put(e.getFirst(), e.getSecond())); // FORGE: This line moved outside the below apply2stable condition + return r.apply2stable((u, p) -> u, entry); + }, + (r1, r2) -> r1.apply2stable((u1, u2) -> u1, r2) + ); + + final Map elements = read.build(); + final T errors = ops.createMap(failed.build().stream()); + + return result.map(unit -> elements).setPartial(elements).mapError(e -> e + " missed input: " + errors); + } + + @Override + public DataResult, T>> decode(final DynamicOps ops, final T input) { + return ops.getMap(input).setLifecycle(Lifecycle.stable()).flatMap(map -> decode(ops, map)).map(r -> Pair.of(r, input)); + } + + @Override + public DataResult encode(final Map input, final DynamicOps ops, final T prefix) { + return encode(input, ops, ops.mapBuilder()).build(prefix); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final LenientUnboundedMapCodec that = (LenientUnboundedMapCodec) o; + return Objects.equals(keyCodec, that.keyCodec) && Objects.equals(elementCodec, that.elementCodec); + } + + @Override + public int hashCode() { + return Objects.hash(keyCodec, elementCodec); + } + + @Override + public String toString() { + return "LenientUnboundedMapCodec[" + keyCodec + " -> " + elementCodec + ']'; + } +}