package net.minecraft.util; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Keyable; import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; import java.util.function.ToIntFunction; import java.util.stream.Collectors; import java.util.stream.Stream; import org.jspecify.annotations.Nullable; public interface StringRepresentable { int PRE_BUILT_MAP_THRESHOLD = 16; String getSerializedName(); static & StringRepresentable> StringRepresentable.EnumCodec fromEnum(final Supplier values) { return fromEnumWithMapping(values, s -> s); } static & StringRepresentable> StringRepresentable.EnumCodec fromEnumWithMapping( final Supplier values, final Function converter ) { E[] valueArray = (E[])values.get(); Function lookupFunction = createNameLookup(valueArray, e -> (String)converter.apply(((StringRepresentable)e).getSerializedName())); return new StringRepresentable.EnumCodec<>(valueArray, lookupFunction); } static Codec fromValues(final Supplier values) { T[] valueArray = (T[])values.get(); Function lookupFunction = createNameLookup(valueArray); ToIntFunction indexLookup = Util.createIndexLookup(Arrays.asList(valueArray)); return new StringRepresentable.StringRepresentableCodec<>(valueArray, lookupFunction, indexLookup); } static Function createNameLookup(final T[] valueArray) { return createNameLookup(valueArray, StringRepresentable::getSerializedName); } static Function createNameLookup(final T[] valueArray, final Function converter) { if (valueArray.length > 16) { Map byName = (Map)Arrays.stream(valueArray).collect(Collectors.toMap(converter, d -> d)); return byName::get; } else { return id -> { for (T value : valueArray) { if (((String)converter.apply(value)).equals(id)) { return value; } } return null; }; } } static Keyable keys(final StringRepresentable[] values) { return new Keyable() { @Override public Stream keys(final DynamicOps ops) { return Arrays.stream(values).map(StringRepresentable::getSerializedName).map(ops::createString); } }; } public static class EnumCodec & StringRepresentable> extends StringRepresentable.StringRepresentableCodec { private final Function resolver; public EnumCodec(final E[] valueArray, final Function nameResolver) { super(valueArray, nameResolver, rec$ -> rec$.ordinal()); this.resolver = nameResolver; } @Nullable public E byName(final String name) { return (E)this.resolver.apply(name); } public E byName(final String name, final E _default) { return (E)Objects.requireNonNullElse(this.byName(name), _default); } public E byName(final String name, final Supplier defaultSupplier) { return (E)Objects.requireNonNullElseGet(this.byName(name), defaultSupplier); } } public static class StringRepresentableCodec implements Codec { private final Codec codec; public StringRepresentableCodec(final S[] valueArray, final Function nameResolver, final ToIntFunction idResolver) { this.codec = ExtraCodecs.orCompressed( Codec.stringResolver(StringRepresentable::getSerializedName, nameResolver), ExtraCodecs.idResolverCodec(idResolver, i -> i >= 0 && i < valueArray.length ? valueArray[i] : null, -1) ); } @Override public DataResult> decode(final DynamicOps ops, final T input) { return this.codec.decode(ops, input); } public DataResult encode(final S input, final DynamicOps ops, final T prefix) { return this.codec.encode(input, ops, prefix); } } }