/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.BiMap * com.google.common.collect.HashBiMap * com.google.common.collect.ImmutableList * com.google.common.collect.ImmutableMap * com.google.common.collect.ImmutableMap$Builder * com.google.common.collect.ImmutableMultimap * com.google.common.collect.ImmutableMultimap$Builder * com.google.common.collect.Multimap * com.google.common.primitives.UnsignedBytes * com.google.gson.JsonElement * com.mojang.authlib.GameProfile * com.mojang.authlib.properties.Property * com.mojang.authlib.properties.PropertyMap * com.mojang.datafixers.kinds.App * com.mojang.datafixers.kinds.Applicative * com.mojang.datafixers.util.Either * com.mojang.datafixers.util.Pair * com.mojang.serialization.Codec * com.mojang.serialization.Codec$ResultFunction * com.mojang.serialization.DataResult * com.mojang.serialization.DataResult$Error * com.mojang.serialization.Decoder * com.mojang.serialization.Dynamic * com.mojang.serialization.DynamicOps * com.mojang.serialization.JavaOps * com.mojang.serialization.JsonOps * com.mojang.serialization.Lifecycle * com.mojang.serialization.MapCodec * com.mojang.serialization.MapLike * com.mojang.serialization.RecordBuilder * com.mojang.serialization.codecs.BaseMapCodec * com.mojang.serialization.codecs.RecordCodecBuilder * it.unimi.dsi.fastutil.floats.FloatArrayList * it.unimi.dsi.fastutil.objects.Object2BooleanMap * it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap * it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap * org.apache.commons.lang3.StringEscapeUtils * org.apache.commons.lang3.mutable.MutableObject * org.joml.AxisAngle4f * org.joml.Matrix4f * org.joml.Matrix4fc * org.joml.Quaternionf * org.joml.Quaternionfc * org.joml.Vector2f * org.joml.Vector2fc * org.joml.Vector3f * org.joml.Vector3fc * org.joml.Vector3i * org.joml.Vector3ic * org.joml.Vector4f * org.joml.Vector4fc * org.jspecify.annotations.Nullable */ 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.ImmutableMultimap; import com.google.common.collect.Multimap; 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.kinds.App; import com.mojang.datafixers.kinds.Applicative; 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.codecs.BaseMapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.floats.FloatArrayList; 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.Collections; import java.util.HexFormat; 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.Set; import java.util.UUID; 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.core.HolderSet; import net.minecraft.core.UUIDUtil; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.resources.Identifier; import net.minecraft.util.ARGB; import net.minecraft.util.StringUtil; import net.minecraft.util.Util; 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.Quaternionfc; import org.joml.Vector2f; import org.joml.Vector2fc; import org.joml.Vector3f; import org.joml.Vector3fc; import org.joml.Vector3i; import org.joml.Vector3ic; import org.joml.Vector4f; import org.joml.Vector4fc; import org.jspecify.annotations.Nullable; public class ExtraCodecs { public static final Codec JSON = ExtraCodecs.converter(JsonOps.INSTANCE); public static final Codec JAVA = ExtraCodecs.converter(JavaOps.INSTANCE); public static final Codec NBT = ExtraCodecs.converter(NbtOps.INSTANCE); public static final Codec VECTOR2F = Codec.FLOAT.listOf().comapFlatMap(input -> Util.fixedSize(input, 2).map(d -> new Vector2f(((Float)d.get(0)).floatValue(), ((Float)d.get(1)).floatValue())), vec -> List.of(Float.valueOf(vec.x()), Float.valueOf(vec.y()))); public static final Codec VECTOR3F = Codec.FLOAT.listOf().comapFlatMap(input -> Util.fixedSize(input, 3).map(d -> new Vector3f(((Float)d.get(0)).floatValue(), ((Float)d.get(1)).floatValue(), ((Float)d.get(2)).floatValue())), vec -> List.of(Float.valueOf(vec.x()), Float.valueOf(vec.y()), Float.valueOf(vec.z()))); public static final Codec VECTOR3I = Codec.INT.listOf().comapFlatMap(input -> Util.fixedSize(input, 3).map(d -> new Vector3i(((Integer)d.get(0)).intValue(), ((Integer)d.get(1)).intValue(), ((Integer)d.get(2)).intValue())), vec -> List.of(Integer.valueOf(vec.x()), Integer.valueOf(vec.y()), Integer.valueOf(vec.z()))); public static final Codec VECTOR4F = Codec.FLOAT.listOf().comapFlatMap(input -> Util.fixedSize(input, 4).map(d -> new Vector4f(((Float)d.get(0)).floatValue(), ((Float)d.get(1)).floatValue(), ((Float)d.get(2)).floatValue(), ((Float)d.get(3)).floatValue())), vec -> List.of(Float.valueOf(vec.x()), Float.valueOf(vec.y()), Float.valueOf(vec.z()), Float.valueOf(vec.w()))); public static final Codec QUATERNIONF_COMPONENTS = Codec.FLOAT.listOf().comapFlatMap(input -> Util.fixedSize(input, 4).map(d -> new Quaternionf(((Float)d.get(0)).floatValue(), ((Float)d.get(1)).floatValue(), ((Float)d.get(2)).floatValue(), ((Float)d.get(3)).floatValue()).normalize()), q -> List.of(Float.valueOf(q.x()), Float.valueOf(q.y()), Float.valueOf(q.z()), Float.valueOf(q.w()))); public static final Codec AXISANGLE4F = RecordCodecBuilder.create(i -> i.group((App)Codec.FLOAT.fieldOf("angle").forGetter(o -> Float.valueOf(o.angle)), (App)VECTOR3F.fieldOf("axis").forGetter(o -> new Vector3f(o.x, o.y, o.z))).apply((Applicative)i, AxisAngle4f::new)); public static final Codec QUATERNIONF = Codec.withAlternative(QUATERNIONF_COMPONENTS, (Codec)AXISANGLE4F.xmap(Quaternionf::new, AxisAngle4f::new)); public static final Codec MATRIX4F = Codec.FLOAT.listOf().comapFlatMap(input -> Util.fixedSize(input, 16).map(l -> { Matrix4f result = new Matrix4f(); for (int i = 0; i < l.size(); ++i) { result.setRowColumn(i >> 2, i & 3, ((Float)l.get(i)).floatValue()); } return result.determineProperties(); }), m -> { FloatArrayList output = new FloatArrayList(16); for (int i = 0; i < 16; ++i) { output.add(m.getRowColumn(i >> 2, i & 3)); } return output; }); private static final String HEX_COLOR_PREFIX = "#"; public static final Codec RGB_COLOR_CODEC = Codec.withAlternative((Codec)Codec.INT, VECTOR3F, v -> ARGB.colorFromFloat(1.0f, v.x(), v.y(), v.z())); public static final Codec ARGB_COLOR_CODEC = Codec.withAlternative((Codec)Codec.INT, VECTOR4F, v -> ARGB.colorFromFloat(v.w(), v.x(), v.y(), v.z())); public static final Codec STRING_RGB_COLOR = Codec.withAlternative((Codec)ExtraCodecs.hexColor(6).xmap(ARGB::opaque, ARGB::transparent), RGB_COLOR_CODEC); public static final Codec STRING_ARGB_COLOR = Codec.withAlternative(ExtraCodecs.hexColor(8), ARGB_COLOR_CODEC); public static final Codec UNSIGNED_BYTE = Codec.BYTE.flatComapMap(UnsignedBytes::toInt, integer -> { if (integer > 255) { return DataResult.error(() -> "Unsigned byte was too large: " + integer + " > 255"); } return DataResult.success((Object)integer.byteValue()); }); public static final Codec NON_NEGATIVE_INT = ExtraCodecs.intRangeWithMessage(0, Integer.MAX_VALUE, n -> "Value must be non-negative: " + n); public static final Codec POSITIVE_INT = ExtraCodecs.intRangeWithMessage(1, Integer.MAX_VALUE, n -> "Value must be positive: " + n); public static final Codec NON_NEGATIVE_LONG = ExtraCodecs.longRangeWithMessage(0L, Long.MAX_VALUE, n -> "Value must be non-negative: " + n); public static final Codec POSITIVE_LONG = ExtraCodecs.longRangeWithMessage(1L, Long.MAX_VALUE, n -> "Value must be positive: " + n); public static final Codec NON_NEGATIVE_FLOAT = ExtraCodecs.floatRangeMinInclusiveWithMessage(0.0f, Float.MAX_VALUE, n -> "Value must be non-negative: " + n); public static final Codec POSITIVE_FLOAT = ExtraCodecs.floatRangeMinExclusiveWithMessage(0.0f, Float.MAX_VALUE, n -> "Value must be positive: " + n); public static final Codec PATTERN = Codec.STRING.comapFlatMap(pattern -> { try { return DataResult.success((Object)Pattern.compile(pattern)); } catch (PatternSyntaxException e) { return DataResult.error(() -> "Invalid regex pattern '" + pattern + "': " + e.getMessage()); } }, Pattern::pattern); public static final Codec INSTANT_ISO8601 = ExtraCodecs.temporalCodec(DateTimeFormatter.ISO_INSTANT).xmap(Instant::from, Function.identity()); public static final Codec BASE64_STRING = Codec.STRING.comapFlatMap(string -> { try { return DataResult.success((Object)Base64.getDecoder().decode((String)string)); } catch (IllegalArgumentException e) { return DataResult.error(() -> "Malformed base64 string"); } }, bytes -> Base64.getEncoder().encodeToString((byte[])bytes)); public static final Codec ESCAPED_STRING = Codec.STRING.comapFlatMap(str -> DataResult.success((Object)StringEscapeUtils.unescapeJava((String)str)), StringEscapeUtils::escapeJava); public static final Codec TAG_OR_ELEMENT_ID = Codec.STRING.comapFlatMap(name -> name.startsWith(HEX_COLOR_PREFIX) ? Identifier.read(name.substring(1)).map(id -> new TagOrElementLocation((Identifier)id, true)) : Identifier.read(name).map(id -> new TagOrElementLocation((Identifier)id, false)), TagOrElementLocation::decoratedId); public static final Function, OptionalLong> toOptionalLong = o -> o.map(OptionalLong::of).orElseGet(OptionalLong::empty); public static final Function> fromOptionalLong = l -> l.isPresent() ? Optional.of(l.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(i -> i.group((App)Codec.STRING.fieldOf("name").forGetter(Property::name), (App)Codec.STRING.fieldOf("value").forGetter(Property::value), (App)Codec.STRING.lenientOptionalFieldOf("signature").forGetter(property -> Optional.ofNullable(property.signature()))).apply((Applicative)i, (name, value, signature) -> new Property(name, value, (String)signature.orElse(null)))); public static final Codec PROPERTY_MAP = Codec.either((Codec)Codec.unboundedMap((Codec)Codec.STRING, (Codec)Codec.STRING.listOf()), (Codec)PROPERTY.listOf()).xmap(mapListEither -> { ImmutableMultimap.Builder result = ImmutableMultimap.builder(); mapListEither.ifLeft(s -> s.forEach((name, properties) -> { for (String property : properties) { result.put(name, (Object)new Property(name, property)); } })).ifRight(properties -> { for (Property property : properties) { result.put((Object)property.name(), (Object)property); } }); return new PropertyMap((Multimap)result.build()); }, propertyMap -> Either.right(propertyMap.values().stream().toList())); public static final Codec PLAYER_NAME = Codec.string((int)0, (int)16).validate(name -> { if (StringUtil.isValidPlayerName(name)) { return DataResult.success((Object)name); } return DataResult.error(() -> "Player name contained disallowed characters: '" + name + "'"); }); public static final Codec AUTHLIB_GAME_PROFILE = ExtraCodecs.gameProfileCodec(UUIDUtil.AUTHLIB_CODEC).codec(); public static final MapCodec STORED_GAME_PROFILE = ExtraCodecs.gameProfileCodec(UUIDUtil.CODEC); public static final Codec NON_EMPTY_STRING = Codec.STRING.validate(value -> value.isEmpty() ? DataResult.error(() -> "Expected non-empty string") : DataResult.success((Object)value)); public static final Codec CODEPOINT = Codec.STRING.comapFlatMap(s -> { int[] codepoint = s.codePoints().toArray(); if (codepoint.length != 1) { return DataResult.error(() -> "Expected one codepoint, got: " + s); } return DataResult.success((Object)codepoint[0]); }, Character::toString); public static final Codec RESOURCE_PATH_CODEC = Codec.STRING.validate(s -> { if (!Identifier.isValidPath(s)) { return DataResult.error(() -> "Invalid string to use as a resource path element: " + s); } return DataResult.success((Object)s); }); public static final Codec UNTRUSTED_URI = Codec.STRING.comapFlatMap(string -> { try { return DataResult.success((Object)Util.parseAndValidateUntrustedUri(string)); } catch (URISyntaxException e) { return DataResult.error(e::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)) continue; return DataResult.error(() -> "Disallowed chat character: '" + c + "'"); } return DataResult.success((Object)string); }); public static Codec converter(DynamicOps ops) { return Codec.PASSTHROUGH.xmap(t -> t.convert(ops).getValue(), t -> new Dynamic(ops, t)); } private static Codec hexColor(int expectedDigits) { long maxValue = (1L << expectedDigits * 4) - 1L; return Codec.STRING.comapFlatMap(string -> { if (!string.startsWith(HEX_COLOR_PREFIX)) { return DataResult.error(() -> "Hex color must begin with #"); } int digits = string.length() - HEX_COLOR_PREFIX.length(); if (digits != expectedDigits) { return DataResult.error(() -> "Hex color is wrong size, expected " + expectedDigits + " digits but got " + digits); } try { long value = HexFormat.fromHexDigitsToLong(string, HEX_COLOR_PREFIX.length(), string.length()); if (value < 0L || value > maxValue) { return DataResult.error(() -> "Color value out of range: " + string); } return DataResult.success((Object)((int)value)); } catch (NumberFormatException e) { return DataResult.error(() -> "Invalid color value: " + string); } }, value -> HEX_COLOR_PREFIX + HexFormat.of().toHexDigits(value.intValue(), expectedDigits)); } public static Codec intervalCodec(Codec

pointCodec, String lowerBoundName, String upperBoundName, BiFunction> makeInterval, Function getMin, Function getMax) { Codec arrayCodec = Codec.list(pointCodec).comapFlatMap(list -> Util.fixedSize(list, 2).flatMap(l -> { Object min = l.get(0); Object max = l.get(1); return (DataResult)makeInterval.apply(min, max); }), p -> ImmutableList.of(getMin.apply(p), getMax.apply(p))); Codec objectCodec = RecordCodecBuilder.create(i -> i.group((App)pointCodec.fieldOf(lowerBoundName).forGetter(Pair::getFirst), (App)pointCodec.fieldOf(upperBoundName).forGetter(Pair::getSecond)).apply((Applicative)i, Pair::of)).comapFlatMap(p -> (DataResult)makeInterval.apply(p.getFirst(), p.getSecond()), i -> Pair.of(getMin.apply(i), getMax.apply(i))); Codec arrayOrObjectCodec = Codec.withAlternative((Codec)arrayCodec, (Codec)objectCodec); return Codec.either(pointCodec, (Codec)arrayOrObjectCodec).comapFlatMap(either -> (DataResult)either.map(min -> (DataResult)makeInterval.apply(min, min), DataResult::success), p -> { Object max; Object min = getMin.apply(p); if (Objects.equals(min, max = getMax.apply(p))) { return Either.left(min); } return Either.right((Object)p); }); } public static Codec.ResultFunction orElsePartial(final A value) { return new Codec.ResultFunction(){ public DataResult> apply(DynamicOps ops, T input, DataResult> a) { MutableObject message = new MutableObject(); Optional result = a.resultOrPartial(arg_0 -> ((MutableObject)message).setValue(arg_0)); if (result.isPresent()) { return a; } return DataResult.error(() -> "(" + (String)message.get() + " -> using default)", (Object)Pair.of((Object)value, input)); } public DataResult coApply(DynamicOps ops, A input, DataResult t) { return t; } public String toString() { return "OrElsePartial[" + String.valueOf(value) + "]"; } }; } public static Codec idResolverCodec(ToIntFunction toInt, IntFunction<@Nullable E> fromInt, int unknownId) { return Codec.INT.flatXmap(id -> Optional.ofNullable(fromInt.apply((int)id)).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Unknown element id: " + id)), e -> { int id = toInt.applyAsInt(e); return id == unknownId ? DataResult.error(() -> "Element with unknown id: " + String.valueOf(e)) : DataResult.success((Object)id); }); } public static Codec idResolverCodec(Codec value, Function fromId, Function toId) { return value.flatXmap(id -> { Object element = fromId.apply(id); return element == null ? DataResult.error(() -> "Unknown element id: " + String.valueOf(id)) : DataResult.success(element); }, e -> { Object id = toId.apply(e); if (id == null) { return DataResult.error(() -> "Element with unknown id: " + String.valueOf(e)); } return DataResult.success(id); }); } public static Codec orCompressed(final Codec normal, final Codec compressed) { return new Codec(){ public DataResult encode(E input, DynamicOps ops, T prefix) { if (ops.compressMaps()) { return compressed.encode(input, ops, prefix); } return normal.encode(input, ops, prefix); } public DataResult> decode(DynamicOps ops, T input) { if (ops.compressMaps()) { return compressed.decode(ops, input); } return normal.decode(ops, input); } public String toString() { return String.valueOf(normal) + " orCompressed " + String.valueOf(compressed); } }; } public static MapCodec orCompressed(final MapCodec normal, final MapCodec compressed) { return new MapCodec(){ public RecordBuilder encode(E input, DynamicOps ops, RecordBuilder prefix) { if (ops.compressMaps()) { return compressed.encode(input, ops, prefix); } return normal.encode(input, ops, prefix); } public DataResult decode(DynamicOps ops, MapLike input) { if (ops.compressMaps()) { return compressed.decode(ops, input); } return normal.decode(ops, input); } public Stream keys(DynamicOps ops) { return compressed.keys(ops); } public String toString() { return String.valueOf(normal) + " orCompressed " + String.valueOf(compressed); } }; } public static Codec overrideLifecycle(Codec codec, final Function decodeLifecycle, final Function encodeLifecycle) { return codec.mapResult(new Codec.ResultFunction(){ public DataResult> apply(DynamicOps ops, T input, DataResult> a) { return a.result().map(r -> a.setLifecycle((Lifecycle)decodeLifecycle.apply(r.getFirst()))).orElse(a); } public DataResult coApply(DynamicOps ops, E input, DataResult t) { return t.setLifecycle((Lifecycle)encodeLifecycle.apply(input)); } public String toString() { return "WithLifecycle[" + String.valueOf(decodeLifecycle) + " " + String.valueOf(encodeLifecycle) + "]"; } }); } public static Codec overrideLifecycle(Codec codec, Function lifecycleGetter) { return ExtraCodecs.overrideLifecycle(codec, lifecycleGetter, lifecycleGetter); } public static StrictUnboundedMapCodec strictUnboundedMap(Codec keyCodec, Codec elementCodec) { return new StrictUnboundedMapCodec(keyCodec, elementCodec); } public static Codec> compactListCodec(Codec elementCodec) { return ExtraCodecs.compactListCodec(elementCodec, elementCodec.listOf()); } public static Codec> compactListCodec(Codec elementCodec, Codec> listCodec) { return Codec.either(listCodec, elementCodec).xmap(e -> (List)e.map(l -> l, List::of), v -> v.size() == 1 ? Either.right(v.getFirst()) : Either.left((Object)v)); } private static Codec intRangeWithMessage(int minInclusive, int maxInclusive, Function error) { return Codec.INT.validate(value -> { if (value.compareTo(minInclusive) >= 0 && value.compareTo(maxInclusive) <= 0) { return DataResult.success((Object)value); } return DataResult.error(() -> (String)error.apply((Integer)value)); }); } public static Codec intRange(int minInclusive, int maxInclusive) { return ExtraCodecs.intRangeWithMessage(minInclusive, maxInclusive, n -> "Value must be within range [" + minInclusive + ";" + maxInclusive + "]: " + n); } private static Codec longRangeWithMessage(long minInclusive, long maxInclusive, Function error) { return Codec.LONG.validate(value -> { if ((long)value.compareTo(minInclusive) >= 0L && (long)value.compareTo(maxInclusive) <= 0L) { return DataResult.success((Object)value); } return DataResult.error(() -> (String)error.apply((Long)value)); }); } public static Codec longRange(int minInclusive, int maxInclusive) { return ExtraCodecs.longRangeWithMessage(minInclusive, maxInclusive, n -> "Value must be within range [" + minInclusive + ";" + maxInclusive + "]: " + n); } private static Codec floatRangeMinInclusiveWithMessage(float minInclusive, float maxInclusive, Function error) { return Codec.FLOAT.validate(value -> { if (value.compareTo(Float.valueOf(minInclusive)) >= 0 && value.compareTo(Float.valueOf(maxInclusive)) <= 0) { return DataResult.success((Object)value); } return DataResult.error(() -> (String)error.apply((Float)value)); }); } private static Codec floatRangeMinExclusiveWithMessage(float minExclusive, float maxInclusive, Function error) { return Codec.FLOAT.validate(value -> { if (value.compareTo(Float.valueOf(minExclusive)) > 0 && value.compareTo(Float.valueOf(maxInclusive)) <= 0) { return DataResult.success((Object)value); } return DataResult.error(() -> (String)error.apply((Float)value)); }); } public static Codec floatRange(float minInclusive, float maxInclusive) { return ExtraCodecs.floatRangeMinInclusiveWithMessage(minInclusive, maxInclusive, n -> "Value must be within range [" + minInclusive + ";" + maxInclusive + "]: " + n); } public static Codec> nonEmptyList(Codec> listCodec) { return listCodec.validate(list -> list.isEmpty() ? DataResult.error(() -> "List must have contents") : DataResult.success((Object)list)); } public static Codec> nonEmptyHolderSet(Codec> listCodec) { return listCodec.validate(list -> { if (list.unwrap().right().filter(List::isEmpty).isPresent()) { return DataResult.error(() -> "List must have contents"); } return DataResult.success((Object)list); }); } public static > Codec nonEmptyMap(Codec mapCodec) { return mapCodec.validate(map -> map.isEmpty() ? DataResult.error(() -> "Map must have contents") : DataResult.success((Object)map)); } public static MapCodec retrieveContext(Function, DataResult> getter) { class ContextRetrievalCodec extends MapCodec { final /* synthetic */ Function val$getter; ContextRetrievalCodec(Function function) { this.val$getter = function; } public RecordBuilder encode(E input, DynamicOps ops, RecordBuilder prefix) { return prefix; } public DataResult decode(DynamicOps ops, MapLike input) { return (DataResult)this.val$getter.apply(ops); } public String toString() { return "ContextRetrievalCodec[" + String.valueOf(this.val$getter) + "]"; } public Stream keys(DynamicOps ops) { return Stream.empty(); } } return new ContextRetrievalCodec(getter); } public static , T> Function> ensureHomogenous(Function typeGetter) { return container -> { Iterator it = container.iterator(); if (it.hasNext()) { Object firstType = typeGetter.apply(it.next()); while (it.hasNext()) { Object next = it.next(); Object nextType = typeGetter.apply(next); if (nextType == firstType) continue; return DataResult.error(() -> "Mixed type list: element " + String.valueOf(next) + " had type " + String.valueOf(nextType) + ", but list is of type " + String.valueOf(firstType)); } } return DataResult.success((Object)container, (Lifecycle)Lifecycle.stable()); }; } public static Codec catchDecoderException(final Codec codec) { return Codec.of(codec, (Decoder)new Decoder(){ public DataResult> decode(DynamicOps ops, T input) { try { return codec.decode(ops, input); } catch (Exception e) { return DataResult.error(() -> "Caught exception decoding " + String.valueOf(input) + ": " + e.getMessage()); } } }); } public static Codec temporalCodec(DateTimeFormatter formatter) { return Codec.STRING.comapFlatMap(s -> { try { return DataResult.success((Object)formatter.parse((CharSequence)s)); } catch (Exception e) { return DataResult.error(e::getMessage); } }, formatter::format); } public static MapCodec asOptionalLong(MapCodec> fieldCodec) { return fieldCodec.xmap(toOptionalLong, fromOptionalLong); } private static MapCodec gameProfileCodec(Codec uuidCodec) { return RecordCodecBuilder.mapCodec(i -> i.group((App)uuidCodec.fieldOf("id").forGetter(GameProfile::id), (App)PLAYER_NAME.fieldOf("name").forGetter(GameProfile::name), (App)PROPERTY_MAP.optionalFieldOf("properties", (Object)PropertyMap.EMPTY).forGetter(GameProfile::properties)).apply((Applicative)i, GameProfile::new)); } public static Codec> sizeLimitedMap(Codec> codec, int maxSizeInclusive) { return codec.validate(map -> { if (map.size() > maxSizeInclusive) { return DataResult.error(() -> "Map is too long: " + map.size() + ", expected range [0-" + maxSizeInclusive + "]"); } return DataResult.success((Object)map); }); } public static Codec> object2BooleanMap(Codec keyCodec) { return Codec.unboundedMap(keyCodec, (Codec)Codec.BOOL).xmap(Object2BooleanOpenHashMap::new, Object2ObjectOpenHashMap::new); } @Deprecated public static MapCodec dispatchOptionalValue(final String typeKey, final String valueKey, final Codec typeCodec, final Function typeGetter, final Function> valueCodec) { return new MapCodec(){ public Stream keys(DynamicOps ops) { return Stream.of(ops.createString(typeKey), ops.createString(valueKey)); } public DataResult decode(DynamicOps ops, MapLike input) { Object typeName = input.get(typeKey); if (typeName == null) { return DataResult.error(() -> "Missing \"" + typeKey + "\" in: " + String.valueOf(input)); } return typeCodec.decode(ops, typeName).flatMap(type -> { Object value = Objects.requireNonNullElseGet(input.get(valueKey), () -> ((DynamicOps)ops).emptyMap()); return ((Codec)valueCodec.apply(type.getFirst())).decode(ops, value).map(Pair::getFirst); }); } public RecordBuilder encode(V input, DynamicOps ops, RecordBuilder builder) { Object type = typeGetter.apply(input); builder.add(typeKey, typeCodec.encodeStart(ops, type)); DataResult parameters = this.encode((Codec)valueCodec.apply(type), input, ops); if (parameters.result().isEmpty() || !Objects.equals(parameters.result().get(), ops.emptyMap())) { builder.add(valueKey, parameters); } return builder; } private DataResult encode(Codec codec, V input, DynamicOps ops) { return codec.encodeStart(ops, input); } }; } public static Codec> optionalEmptyMap(final Codec codec) { return new Codec>(){ public DataResult, T>> decode(DynamicOps ops, T input) { if (7.isEmptyMap(ops, input)) { return DataResult.success((Object)Pair.of(Optional.empty(), input)); } return codec.decode(ops, input).map(pair -> pair.mapFirst(Optional::of)); } private static boolean isEmptyMap(DynamicOps ops, T input) { Optional map = ops.getMap(input).result(); return map.isPresent() && ((MapLike)map.get()).entries().findAny().isEmpty(); } public DataResult encode(Optional input, DynamicOps ops, T prefix) { if (input.isEmpty()) { return DataResult.success((Object)ops.emptyMap()); } return codec.encode(input.get(), ops, prefix); } }; } @Deprecated public static > Codec legacyEnum(Function valueOf) { return Codec.STRING.comapFlatMap(key -> { try { return DataResult.success((Object)((Enum)valueOf.apply((String)key))); } catch (IllegalArgumentException ignored) { return DataResult.error(() -> "No value with id: " + key); } }, Enum::toString); } public record StrictUnboundedMapCodec(Codec keyCodec, Codec elementCodec) implements BaseMapCodec, Codec> { public DataResult> decode(DynamicOps ops, MapLike input) { ImmutableMap.Builder read = ImmutableMap.builder(); for (Pair pair : input.entries().toList()) { DataResult v; DataResult k = this.keyCodec().parse(ops, pair.getFirst()); DataResult entry = k.apply2stable(Pair::of, v = this.elementCodec().parse(ops, pair.getSecond())); Optional error = entry.error(); if (error.isPresent()) { String errorMessage = ((DataResult.Error)error.get()).message(); return DataResult.error(() -> { if (k.result().isPresent()) { return "Map entry '" + String.valueOf(k.result().get()) + "' : " + errorMessage; } return errorMessage; }); } if (entry.result().isPresent()) { Pair kvPair = (Pair)entry.result().get(); read.put(kvPair.getFirst(), kvPair.getSecond()); continue; } return DataResult.error(() -> "Empty or invalid map contents are not allowed"); } ImmutableMap elements = read.build(); return DataResult.success((Object)elements); } public DataResult, T>> decode(DynamicOps ops, T input) { return ops.getMap(input).setLifecycle(Lifecycle.stable()).flatMap(map -> this.decode(ops, (Object)map)).map(r -> Pair.of((Object)r, (Object)input)); } public DataResult encode(Map input, DynamicOps ops, T prefix) { return this.encode(input, ops, ops.mapBuilder()).build(prefix); } @Override public String toString() { return "StrictUnboundedMapCodec[" + String.valueOf(this.keyCodec) + " -> " + String.valueOf(this.elementCodec) + "]"; } } public record TagOrElementLocation(Identifier id, boolean tag) { @Override public String toString() { return this.decoratedId(); } private String decoratedId() { return this.tag ? ExtraCodecs.HEX_COLOR_PREFIX + String.valueOf(this.id) : this.id.toString(); } } public static class LateBoundIdMapper { private final BiMap idToValue = HashBiMap.create(); public Codec codec(Codec idCodec) { BiMap valueToId = this.idToValue.inverse(); return ExtraCodecs.idResolverCodec(idCodec, arg_0 -> this.idToValue.get(arg_0), arg_0 -> valueToId.get(arg_0)); } public LateBoundIdMapper put(I id, V value) { Objects.requireNonNull(value, () -> "Value for " + String.valueOf(id) + " is null"); this.idToValue.put(id, value); return this; } public Set values() { return Collections.unmodifiableSet(this.idToValue.values()); } } }