package net.minecraft.util; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.google.common.primitives.UnsignedBytes; import com.google.gson.JsonElement; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Decoder; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JavaOps; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapLike; import com.mojang.serialization.RecordBuilder; import com.mojang.serialization.Codec.ResultFunction; import com.mojang.serialization.DataResult.Error; import com.mojang.serialization.codecs.BaseMapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.floats.FloatList; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import java.net.URI; import java.net.URISyntaxException; import java.time.Instant; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.Arrays; import java.util.Base64; import java.util.BitSet; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.OptionalLong; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.ToIntFunction; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.Stream; import net.minecraft.Util; import net.minecraft.core.HolderSet; import net.minecraft.core.UUIDUtil; import net.minecraft.resources.ResourceLocation; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.mutable.MutableObject; import org.joml.AxisAngle4f; import org.joml.Matrix4f; import org.joml.Matrix4fc; import org.joml.Quaternionf; import org.joml.Vector3f; import org.joml.Vector4f; public class ExtraCodecs { public static final Codec JSON = converter(JsonOps.INSTANCE); public static final Codec JAVA = converter(JavaOps.INSTANCE); public static final Codec VECTOR3F = Codec.FLOAT .listOf() .comapFlatMap( list -> Util.fixedSize(list, 3).map(listx -> new Vector3f((Float)listx.get(0), (Float)listx.get(1), (Float)listx.get(2))), vector3f -> List.of(vector3f.x(), vector3f.y(), vector3f.z()) ); public static final Codec VECTOR4F = Codec.FLOAT .listOf() .comapFlatMap( list -> Util.fixedSize(list, 4).map(listx -> new Vector4f((Float)listx.get(0), (Float)listx.get(1), (Float)listx.get(2), (Float)listx.get(3))), vector4f -> List.of(vector4f.x(), vector4f.y(), vector4f.z(), vector4f.w()) ); public static final Codec QUATERNIONF_COMPONENTS = Codec.FLOAT .listOf() .comapFlatMap( list -> Util.fixedSize(list, 4) .map(listx -> new Quaternionf((Float)listx.get(0), (Float)listx.get(1), (Float)listx.get(2), (Float)listx.get(3)).normalize()), quaternionf -> List.of(quaternionf.x, quaternionf.y, quaternionf.z, quaternionf.w) ); public static final Codec AXISANGLE4F = RecordCodecBuilder.create( instance -> instance.group( Codec.FLOAT.fieldOf("angle").forGetter(axisAngle4f -> axisAngle4f.angle), VECTOR3F.fieldOf("axis").forGetter(axisAngle4f -> new Vector3f(axisAngle4f.x, axisAngle4f.y, axisAngle4f.z)) ) .apply(instance, AxisAngle4f::new) ); public static final Codec QUATERNIONF = Codec.withAlternative(QUATERNIONF_COMPONENTS, AXISANGLE4F.xmap(Quaternionf::new, AxisAngle4f::new)); public static final Codec MATRIX4F = Codec.FLOAT.listOf().comapFlatMap(list -> Util.fixedSize(list, 16).map(listx -> { Matrix4f matrix4f = new Matrix4f(); for (int i = 0; i < listx.size(); i++) { matrix4f.setRowColumn(i >> 2, i & 3, (Float)listx.get(i)); } return matrix4f.determineProperties(); }), matrix4fc -> { FloatList floatList = new FloatArrayList(16); for (int i = 0; i < 16; i++) { floatList.add(matrix4fc.getRowColumn(i >> 2, i & 3)); } return floatList; }); public static final Codec RGB_COLOR_CODEC = Codec.withAlternative( Codec.INT, VECTOR3F, vector3f -> ARGB.colorFromFloat(1.0F, vector3f.x(), vector3f.y(), vector3f.z()) ); public static final Codec ARGB_COLOR_CODEC = Codec.withAlternative( Codec.INT, VECTOR4F, vector4f -> ARGB.colorFromFloat(vector4f.w(), vector4f.x(), vector4f.y(), vector4f.z()) ); public static final Codec UNSIGNED_BYTE = Codec.BYTE .flatComapMap( UnsignedBytes::toInt, integer -> integer > 255 ? DataResult.error(() -> "Unsigned byte was too large: " + integer + " > 255") : DataResult.success(integer.byteValue()) ); public static final Codec NON_NEGATIVE_INT = intRangeWithMessage(0, Integer.MAX_VALUE, integer -> "Value must be non-negative: " + integer); public static final Codec POSITIVE_INT = intRangeWithMessage(1, Integer.MAX_VALUE, integer -> "Value must be positive: " + integer); public static final Codec NON_NEGATIVE_FLOAT = floatRangeMinInclusiveWithMessage( 0.0F, Float.MAX_VALUE, float_ -> "Value must be non-negative: " + float_ ); public static final Codec POSITIVE_FLOAT = floatRangeMinExclusiveWithMessage(0.0F, Float.MAX_VALUE, float_ -> "Value must be positive: " + float_); public static final Codec PATTERN = Codec.STRING.comapFlatMap(string -> { try { return DataResult.success(Pattern.compile(string)); } catch (PatternSyntaxException var2) { return DataResult.error(() -> "Invalid regex pattern '" + string + "': " + var2.getMessage()); } }, Pattern::pattern); public static final Codec INSTANT_ISO8601 = temporalCodec(DateTimeFormatter.ISO_INSTANT).xmap(Instant::from, Function.identity()); public static final Codec BASE64_STRING = Codec.STRING.comapFlatMap(string -> { try { return DataResult.success(Base64.getDecoder().decode(string)); } catch (IllegalArgumentException var2) { return DataResult.error(() -> "Malformed base64 string"); } }, bs -> Base64.getEncoder().encodeToString(bs)); public static final Codec ESCAPED_STRING = Codec.STRING .comapFlatMap(string -> DataResult.success(StringEscapeUtils.unescapeJava(string)), StringEscapeUtils::escapeJava); public static final Codec TAG_OR_ELEMENT_ID = Codec.STRING .comapFlatMap( string -> string.startsWith("#") ? ResourceLocation.read(string.substring(1)).map(resourceLocation -> new ExtraCodecs.TagOrElementLocation(resourceLocation, true)) : ResourceLocation.read(string).map(resourceLocation -> new ExtraCodecs.TagOrElementLocation(resourceLocation, false)), ExtraCodecs.TagOrElementLocation::decoratedId ); public static final Function, OptionalLong> toOptionalLong = optional -> (OptionalLong)optional.map(OptionalLong::of) .orElseGet(OptionalLong::empty); public static final Function> fromOptionalLong = optionalLong -> optionalLong.isPresent() ? Optional.of(optionalLong.getAsLong()) : Optional.empty(); public static final Codec BIT_SET = Codec.LONG_STREAM .xmap(longStream -> BitSet.valueOf(longStream.toArray()), bitSet -> Arrays.stream(bitSet.toLongArray())); private static final Codec PROPERTY = RecordCodecBuilder.create( instance -> instance.group( Codec.STRING.fieldOf("name").forGetter(Property::name), Codec.STRING.fieldOf("value").forGetter(Property::value), Codec.STRING.lenientOptionalFieldOf("signature").forGetter(property -> Optional.ofNullable(property.signature())) ) .apply(instance, (string, string2, optional) -> new Property(string, string2, (String)optional.orElse(null))) ); public static final Codec PROPERTY_MAP = Codec.either(Codec.unboundedMap(Codec.STRING, Codec.STRING.listOf()), PROPERTY.listOf()) .xmap(either -> { PropertyMap propertyMap = new PropertyMap(); either.ifLeft(map -> map.forEach((string, list) -> { for (String string2 : list) { propertyMap.put(string, new Property(string, string2)); } })).ifRight(list -> { for (Property property : list) { propertyMap.put(property.name(), property); } }); return propertyMap; }, propertyMap -> Either.right(propertyMap.values().stream().toList())); public static final Codec PLAYER_NAME = Codec.string(0, 16) .validate( string -> StringUtil.isValidPlayerName(string) ? DataResult.success(string) : DataResult.error(() -> "Player name contained disallowed characters: '" + string + "'") ); private static final MapCodec GAME_PROFILE_WITHOUT_PROPERTIES = RecordCodecBuilder.mapCodec( instance -> instance.group(UUIDUtil.AUTHLIB_CODEC.fieldOf("id").forGetter(GameProfile::getId), PLAYER_NAME.fieldOf("name").forGetter(GameProfile::getName)) .apply(instance, GameProfile::new) ); public static final Codec GAME_PROFILE = RecordCodecBuilder.create( instance -> instance.group( GAME_PROFILE_WITHOUT_PROPERTIES.forGetter(Function.identity()), PROPERTY_MAP.lenientOptionalFieldOf("properties", new PropertyMap()).forGetter(GameProfile::getProperties) ) .apply(instance, (gameProfile, propertyMap) -> { propertyMap.forEach((string, property) -> gameProfile.getProperties().put(string, property)); return gameProfile; }) ); public static final Codec NON_EMPTY_STRING = Codec.STRING .validate(string -> string.isEmpty() ? DataResult.error(() -> "Expected non-empty string") : DataResult.success(string)); public static final Codec CODEPOINT = Codec.STRING.comapFlatMap(string -> { int[] is = string.codePoints().toArray(); return is.length != 1 ? DataResult.error(() -> "Expected one codepoint, got: " + string) : DataResult.success(is[0]); }, Character::toString); public static final Codec RESOURCE_PATH_CODEC = Codec.STRING .validate( string -> !ResourceLocation.isValidPath(string) ? DataResult.error(() -> "Invalid string to use as a resource path element: " + string) : DataResult.success(string) ); public static final Codec UNTRUSTED_URI = Codec.STRING.comapFlatMap(string -> { try { return DataResult.success(Util.parseAndValidateUntrustedUri(string)); } catch (URISyntaxException var2) { return DataResult.error(var2::getMessage); } }, URI::toString); public static final Codec CHAT_STRING = Codec.STRING.validate(string -> { for (int i = 0; i < string.length(); i++) { char c = string.charAt(i); if (!StringUtil.isAllowedChatCharacter(c)) { return DataResult.error(() -> "Disallowed chat character: '" + c + "'"); } } return DataResult.success(string); }); public static Codec converter(DynamicOps ops) { return Codec.PASSTHROUGH.xmap(dynamic -> dynamic.convert(ops).getValue(), object -> new Dynamic<>(ops, (T)object)); } public static Codec intervalCodec( Codec

codec, String minFieldName, String maxFieldName, BiFunction> factory, Function minGetter, Function maxGetter ) { Codec codec2 = Codec.list(codec).comapFlatMap(list -> Util.fixedSize(list, 2).flatMap(listx -> { P object = (P)listx.get(0); P object2 = (P)listx.get(1); return (DataResult)factory.apply(object, object2); }), object -> ImmutableList.of(minGetter.apply(object), maxGetter.apply(object))); Codec codec3 = RecordCodecBuilder.create( instance -> instance.group(codec.fieldOf(minFieldName).forGetter(Pair::getFirst), codec.fieldOf(maxFieldName).forGetter(Pair::getSecond)) .apply(instance, Pair::of) ) .comapFlatMap(pair -> (DataResult)factory.apply(pair.getFirst(), pair.getSecond()), object -> Pair.of(minGetter.apply(object), maxGetter.apply(object))); Codec codec4 = Codec.withAlternative(codec2, codec3); return Codec.either(codec, codec4).comapFlatMap(either -> either.map(object -> (DataResult)factory.apply(object, object), DataResult::success), object -> { P object2 = (P)minGetter.apply(object); P object3 = (P)maxGetter.apply(object); return Objects.equals(object2, object3) ? Either.left(object2) : Either.right(object); }); } public static ResultFunction orElsePartial(A value) { return new ResultFunction() { @Override public DataResult> apply(DynamicOps dynamicOps, T object, DataResult> dataResult) { MutableObject mutableObject = new MutableObject<>(); Optional> optional = dataResult.resultOrPartial(mutableObject::setValue); return optional.isPresent() ? dataResult : DataResult.error(() -> "(" + mutableObject.getValue() + " -> using default)", Pair.of(value, object)); } @Override public DataResult coApply(DynamicOps dynamicOps, A object, DataResult dataResult) { return dataResult; } public String toString() { return "OrElsePartial[" + value + "]"; } }; } public static Codec idResolverCodec(ToIntFunction encoder, IntFunction decoder, int notFoundValue) { return Codec.INT .flatXmap( integer -> (DataResult)Optional.ofNullable(decoder.apply(integer)) .map(DataResult::success) .orElseGet(() -> DataResult.error(() -> "Unknown element id: " + integer)), object -> { int j = encoder.applyAsInt(object); return j == notFoundValue ? DataResult.error(() -> "Element with unknown id: " + object) : DataResult.success(j); } ); } public static Codec idResolverCodec(Codec idCodec, Function idToValue, Function valueToId) { return idCodec.flatXmap(object -> { E object2 = (E)idToValue.apply(object); return object2 == null ? DataResult.error(() -> "Unknown element id: " + object) : DataResult.success(object2); }, object -> { I object2 = (I)valueToId.apply(object); return object2 == null ? DataResult.error(() -> "Element with unknown id: " + object) : DataResult.success(object2); }); } public static Codec orCompressed(Codec first, Codec second) { return new Codec() { @Override public DataResult encode(E object, DynamicOps dynamicOps, T object2) { return dynamicOps.compressMaps() ? second.encode(object, dynamicOps, object2) : first.encode(object, dynamicOps, object2); } @Override public DataResult> decode(DynamicOps dynamicOps, T object) { return dynamicOps.compressMaps() ? second.decode(dynamicOps, object) : first.decode(dynamicOps, object); } public String toString() { return first + " orCompressed " + second; } }; } public static MapCodec orCompressed(MapCodec first, MapCodec second) { return new MapCodec() { @Override public RecordBuilder encode(E object, DynamicOps dynamicOps, RecordBuilder recordBuilder) { return dynamicOps.compressMaps() ? second.encode(object, dynamicOps, recordBuilder) : first.encode(object, dynamicOps, recordBuilder); } @Override public DataResult decode(DynamicOps dynamicOps, MapLike mapLike) { return dynamicOps.compressMaps() ? second.decode(dynamicOps, mapLike) : first.decode(dynamicOps, mapLike); } @Override public Stream keys(DynamicOps dynamicOps) { return second.keys(dynamicOps); } public String toString() { return first + " orCompressed " + second; } }; } public static Codec overrideLifecycle(Codec codec, Function applyLifecycle, Function coApplyLifecycle) { return codec.mapResult( new ResultFunction() { @Override public DataResult> apply(DynamicOps dynamicOps, T object, DataResult> dataResult) { return (DataResult>)dataResult.result() .map(pair -> dataResult.setLifecycle((Lifecycle)applyLifecycle.apply(pair.getFirst()))) .orElse(dataResult); } @Override public DataResult coApply(DynamicOps dynamicOps, E object, DataResult dataResult) { return dataResult.setLifecycle((Lifecycle)coApplyLifecycle.apply(object)); } public String toString() { return "WithLifecycle[" + applyLifecycle + " " + coApplyLifecycle + "]"; } } ); } public static Codec overrideLifecycle(Codec codec, Function lifecycleGetter) { return overrideLifecycle(codec, lifecycleGetter, lifecycleGetter); } public static ExtraCodecs.StrictUnboundedMapCodec strictUnboundedMap(Codec key, Codec value) { return new ExtraCodecs.StrictUnboundedMapCodec<>(key, value); } public static Codec> compactListCodec(Codec elementCodec) { return compactListCodec(elementCodec, elementCodec.listOf()); } public static Codec> compactListCodec(Codec elementCodec, Codec> listCodec) { return Codec.either(listCodec, elementCodec) .xmap(either -> either.map(list -> list, List::of), list -> list.size() == 1 ? Either.right(list.getFirst()) : Either.left(list)); } private static Codec intRangeWithMessage(int min, int max, Function errorMessage) { return Codec.INT .validate( integer -> integer.compareTo(min) >= 0 && integer.compareTo(max) <= 0 ? DataResult.success(integer) : DataResult.error(() -> (String)errorMessage.apply(integer)) ); } public static Codec intRange(int min, int max) { return intRangeWithMessage(min, max, integer -> "Value must be within range [" + min + ";" + max + "]: " + integer); } private static Codec floatRangeMinInclusiveWithMessage(float min, float max, Function errorMessage) { return Codec.FLOAT .validate( float_ -> float_.compareTo(min) >= 0 && float_.compareTo(max) <= 0 ? DataResult.success(float_) : DataResult.error(() -> (String)errorMessage.apply(float_)) ); } private static Codec floatRangeMinExclusiveWithMessage(float min, float max, Function errorMessage) { return Codec.FLOAT .validate( float_ -> float_.compareTo(min) > 0 && float_.compareTo(max) <= 0 ? DataResult.success(float_) : DataResult.error(() -> (String)errorMessage.apply(float_)) ); } public static Codec floatRange(float min, float max) { return floatRangeMinInclusiveWithMessage(min, max, float_ -> "Value must be within range [" + min + ";" + max + "]: " + float_); } public static Codec> nonEmptyList(Codec> codec) { return codec.validate(list -> list.isEmpty() ? DataResult.error(() -> "List must have contents") : DataResult.success(list)); } public static Codec> nonEmptyHolderSet(Codec> codec) { return codec.validate( holderSet -> holderSet.unwrap().right().filter(List::isEmpty).isPresent() ? DataResult.error(() -> "List must have contents") : DataResult.success(holderSet) ); } public static > Codec nonEmptyMap(Codec mapCodec) { return mapCodec.validate(map -> map.isEmpty() ? DataResult.error(() -> "Map must have contents") : DataResult.success(map)); } public static MapCodec retrieveContext(Function, DataResult> retriever) { class ContextRetrievalCodec extends MapCodec { @Override public RecordBuilder encode(E object, DynamicOps dynamicOps, RecordBuilder recordBuilder) { return recordBuilder; } @Override public DataResult decode(DynamicOps dynamicOps, MapLike mapLike) { return (DataResult)retriever.apply(dynamicOps); } public String toString() { return "ContextRetrievalCodec[" + retriever + "]"; } @Override public Stream keys(DynamicOps dynamicOps) { return Stream.empty(); } } return new ContextRetrievalCodec(); } public static , T> Function> ensureHomogenous(Function typeGetter) { return collection -> { Iterator iterator = collection.iterator(); if (iterator.hasNext()) { T object = (T)typeGetter.apply(iterator.next()); while (iterator.hasNext()) { E object2 = (E)iterator.next(); T object3 = (T)typeGetter.apply(object2); if (object3 != object) { return DataResult.error(() -> "Mixed type list: element " + object2 + " had type " + object3 + ", but list is of type " + object); } } } return DataResult.success(collection, Lifecycle.stable()); }; } public static Codec catchDecoderException(Codec codec) { return Codec.of(codec, new Decoder() { @Override public DataResult> decode(DynamicOps dynamicOps, T object) { try { return codec.decode(dynamicOps, object); } catch (Exception var4) { return DataResult.error(() -> "Caught exception decoding " + object + ": " + var4.getMessage()); } } }); } public static Codec temporalCodec(DateTimeFormatter dateTimeFormatter) { return Codec.STRING.comapFlatMap(string -> { try { return DataResult.success(dateTimeFormatter.parse(string)); } catch (Exception var3) { return DataResult.error(var3::getMessage); } }, dateTimeFormatter::format); } public static MapCodec asOptionalLong(MapCodec> codec) { return codec.xmap(toOptionalLong, fromOptionalLong); } public static Codec> sizeLimitedMap(Codec> mapCodec, int maxSize) { return mapCodec.validate( map -> map.size() > maxSize ? DataResult.error(() -> "Map is too long: " + map.size() + ", expected range [0-" + maxSize + "]") : DataResult.success(map) ); } public static Codec> object2BooleanMap(Codec codec) { return Codec.unboundedMap(codec, Codec.BOOL).xmap(Object2BooleanOpenHashMap::new, Object2ObjectOpenHashMap::new); } @Deprecated public static MapCodec dispatchOptionalValue( String key1, String key2, Codec codec, Function keyGetter, Function> codecGetter ) { return new MapCodec() { @Override public Stream keys(DynamicOps dynamicOps) { return Stream.of(dynamicOps.createString(key1), dynamicOps.createString(key2)); } @Override public DataResult decode(DynamicOps dynamicOps, MapLike mapLike) { T object = mapLike.get(key1); return object == null ? DataResult.error(() -> "Missing \"" + key1 + "\" in: " + mapLike) : codec.decode(dynamicOps, object).flatMap(pair -> { T objectx = (T)Objects.requireNonNullElseGet(mapLike.get(key2), dynamicOps::emptyMap); return ((Codec)codecGetter.apply(pair.getFirst())).decode(dynamicOps, objectx).map(Pair::getFirst); }); } @Override public RecordBuilder encode(V object, DynamicOps dynamicOps, RecordBuilder recordBuilder) { K object2 = (K)keyGetter.apply(object); recordBuilder.add(key1, codec.encodeStart(dynamicOps, object2)); DataResult dataResult = this.encode((Codec)codecGetter.apply(object2), object, dynamicOps); if (dataResult.result().isEmpty() || !Objects.equals(dataResult.result().get(), dynamicOps.emptyMap())) { recordBuilder.add(key2, dataResult); } return recordBuilder; } private DataResult encode(Codec valueCodec, V value, DynamicOps ops) { return valueCodec.encodeStart(ops, (V2)value); } }; } public static Codec> optionalEmptyMap(Codec codec) { return new Codec>() { @Override public DataResult, T>> decode(DynamicOps dynamicOps, T object) { return isEmptyMap(dynamicOps, object) ? DataResult.success(Pair.of(Optional.empty(), object)) : codec.decode(dynamicOps, object).map(pair -> pair.mapFirst(Optional::of)); } private static boolean isEmptyMap(DynamicOps ops, T value) { Optional> optional = ops.getMap(value).result(); return optional.isPresent() && ((MapLike)optional.get()).entries().findAny().isEmpty(); } public DataResult encode(Optional input, DynamicOps ops, T value) { return input.isEmpty() ? DataResult.success(ops.emptyMap()) : codec.encode((A)input.get(), ops, value); } }; } @Deprecated public static > Codec legacyEnum(Function fromString) { return Codec.STRING.comapFlatMap(string -> { try { return DataResult.success((Enum)fromString.apply(string)); } catch (IllegalArgumentException var3) { return DataResult.error(() -> "No value with id: " + string); } }, Enum::toString); } public static class LateBoundIdMapper { private final BiMap idToValue = HashBiMap.create(); public Codec codec(Codec idCodec) { BiMap biMap = this.idToValue.inverse(); return ExtraCodecs.idResolverCodec(idCodec, this.idToValue::get, biMap::get); } public ExtraCodecs.LateBoundIdMapper put(I id, V value) { Objects.requireNonNull(value, () -> "Value for " + id + " is null"); this.idToValue.put(id, value); return this; } } public record StrictUnboundedMapCodec(Codec a, Codec b) implements Codec>, BaseMapCodec { @Override public DataResult> decode(DynamicOps dynamicOps, MapLike mapLike) { Builder builder = ImmutableMap.builder(); for (Pair pair : mapLike.entries().toList()) { DataResult dataResult = this.keyCodec().parse(dynamicOps, pair.getFirst()); DataResult dataResult2 = this.elementCodec().parse(dynamicOps, pair.getSecond()); DataResult> dataResult3 = dataResult.apply2stable(Pair::of, dataResult2); Optional>> optional = dataResult3.error(); if (optional.isPresent()) { String string = ((Error)optional.get()).message(); return DataResult.error(() -> dataResult.result().isPresent() ? "Map entry '" + dataResult.result().get() + "' : " + string : string); } if (!dataResult3.result().isPresent()) { return DataResult.error(() -> "Empty or invalid map contents are not allowed"); } Pair pair2 = (Pair)dataResult3.result().get(); builder.put(pair2.getFirst(), pair2.getSecond()); } Map map = builder.build(); return DataResult.success(map); } @Override public DataResult, T>> decode(DynamicOps dynamicOps, T object) { return dynamicOps.getMap(object).setLifecycle(Lifecycle.stable()).flatMap(mapLike -> this.decode(dynamicOps, mapLike)).map(map -> Pair.of(map, object)); } public DataResult encode(Map input, DynamicOps ops, T value) { return this.encode(input, ops, ops.mapBuilder()).build(value); } public String toString() { return "StrictUnboundedMapCodec[" + this.a + " -> " + this.b + "]"; } @Override public Codec keyCodec() { return this.a; } @Override public Codec elementCodec() { return this.b; } } public record TagOrElementLocation(ResourceLocation id, boolean tag) { public String toString() { return this.decoratedId(); } private String decoratedId() { return this.tag ? "#" + this.id : this.id.toString(); } } }