package net.minecraft.resources; 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.Lifecycle; import java.util.Optional; import net.minecraft.core.Holder; import net.minecraft.core.HolderGetter; import net.minecraft.core.HolderOwner; import net.minecraft.core.Registry; public final class RegistryFileCodec implements Codec> { private final ResourceKey> registryKey; private final Codec elementCodec; private final boolean allowInline; public static RegistryFileCodec create(final ResourceKey> registryKey, final Codec elementCodec) { return create(registryKey, elementCodec, true); } public static RegistryFileCodec create(final ResourceKey> registryKey, final Codec elementCodec, final boolean allowInline) { return new RegistryFileCodec<>(registryKey, elementCodec, allowInline); } private RegistryFileCodec(final ResourceKey> registryKey, final Codec elementCodec, final boolean allowInline) { this.registryKey = registryKey; this.elementCodec = elementCodec; this.allowInline = allowInline; } public DataResult encode(final Holder input, final DynamicOps ops, final T prefix) { if (ops instanceof RegistryOps registryOps) { Optional> maybeOwner = registryOps.owner(this.registryKey); if (maybeOwner.isPresent()) { if (!input.canSerializeIn((HolderOwner)maybeOwner.get())) { return DataResult.error(() -> "Element " + input + " is not valid in current registry set"); } return input.unwrap().map(id -> Identifier.CODEC.encode(id.identifier(), ops, prefix), value -> this.elementCodec.encode((E)value, ops, prefix)); } } return this.elementCodec.encode(input.value(), ops, prefix); } @Override public DataResult, T>> decode(final DynamicOps ops, final T input) { if (ops instanceof RegistryOps registryOps) { Optional> maybeLookup = registryOps.getter(this.registryKey); if (maybeLookup.isEmpty()) { return DataResult.error(() -> "Registry does not exist: " + this.registryKey); } else { HolderGetter lookup = (HolderGetter)maybeLookup.get(); DataResult> decoded = Identifier.CODEC.decode(ops, input); if (decoded.result().isEmpty()) { return !this.allowInline ? DataResult.error(() -> "Inline definitions not allowed here") : this.elementCodec.decode(ops, input).map(p -> p.mapFirst(Holder::direct)); } else { Pair pair = (Pair)decoded.result().get(); ResourceKey elementKey = ResourceKey.create(this.registryKey, pair.getFirst()); return ((DataResult)lookup.get(elementKey).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Failed to get element " + elementKey))) ., T>>map(h -> Pair.of(h, pair.getSecond())) .setLifecycle(Lifecycle.stable()); } } } else { return this.elementCodec.decode(ops, input).map(p -> p.mapFirst(Holder::direct)); } } public String toString() { return "RegistryFileCodec[" + this.registryKey + " " + this.elementCodec + "]"; } }