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 net.minecraft.Util; import org.jetbrains.annotations.Nullable; public interface StringRepresentable { int PRE_BUILT_MAP_THRESHOLD = 16; String getSerializedName(); static & StringRepresentable> StringRepresentable.EnumCodec fromEnum(Supplier elementsSupplier) { return fromEnumWithMapping(elementsSupplier, string -> string); } static & StringRepresentable> StringRepresentable.EnumCodec fromEnumWithMapping( Supplier enumValues, Function keyFunction ) { E[] enums = (E[])enumValues.get(); Function function = createNameLookup(enums, keyFunction); return new StringRepresentable.EnumCodec<>(enums, function); } static Codec fromValues(Supplier valuesSupplier) { T[] stringRepresentables = (T[])valuesSupplier.get(); Function function = createNameLookup(stringRepresentables, string -> string); ToIntFunction toIntFunction = Util.createIndexLookup(Arrays.asList(stringRepresentables)); return new StringRepresentable.StringRepresentableCodec<>(stringRepresentables, function, toIntFunction); } static Function createNameLookup(T[] values, Function keyFunction) { if (values.length > 16) { Map map = (Map)Arrays.stream(values) .collect( Collectors.toMap(stringRepresentable -> (String)keyFunction.apply(stringRepresentable.getSerializedName()), stringRepresentable -> stringRepresentable) ); return string -> string == null ? null : (StringRepresentable)map.get(string); } else { return string -> { for (T stringRepresentable : values) { if (((String)keyFunction.apply(stringRepresentable.getSerializedName())).equals(string)) { return stringRepresentable; } } return null; }; } } static Keyable keys(StringRepresentable[] serializables) { return new Keyable() { @Override public Stream keys(DynamicOps dynamicOps) { return Arrays.stream(serializables).map(StringRepresentable::getSerializedName).map(dynamicOps::createString); } }; } public static class EnumCodec & StringRepresentable> extends StringRepresentable.StringRepresentableCodec { private final Function resolver; public EnumCodec(E[] values, Function resolver) { super(values, resolver, object -> ((Enum)object).ordinal()); this.resolver = resolver; } @Nullable public E byName(@Nullable String name) { return (E)this.resolver.apply(name); } public E byName(@Nullable String name, E defaultValue) { return (E)Objects.requireNonNullElse(this.byName(name), defaultValue); } public E byName(@Nullable String name, Supplier defaultValue) { return (E)Objects.requireNonNullElseGet(this.byName(name), defaultValue); } } public static class StringRepresentableCodec implements Codec { private final Codec codec; public StringRepresentableCodec(S[] values, Function nameLookup, ToIntFunction indexLookup) { this.codec = ExtraCodecs.orCompressed( Codec.stringResolver(StringRepresentable::getSerializedName, nameLookup), ExtraCodecs.idResolverCodec(indexLookup, i -> i >= 0 && i < values.length ? values[i] : null, -1) ); } @Override public DataResult> decode(DynamicOps dynamicOps, T object) { return this.codec.decode(dynamicOps, object); } public DataResult encode(S input, DynamicOps ops, T prefix) { return this.codec.encode(input, ops, prefix); } } }