package net.minecraft.util; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JavaOps; import com.mojang.serialization.Lifecycle; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import net.minecraft.core.Holder; import net.minecraft.core.HolderGetter; import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderOwner; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; public class PlaceholderLookupProvider implements HolderGetter.Provider { private final HolderLookup.Provider context; private final PlaceholderLookupProvider.UniversalLookup lookup = new PlaceholderLookupProvider.UniversalLookup(); private final Map, Holder.Reference> holders = new HashMap(); private final Map, HolderSet.Named> holderSets = new HashMap(); public PlaceholderLookupProvider(final HolderLookup.Provider context) { this.context = context; } @Override public Optional> lookup(final ResourceKey> key) { return Optional.of(this.lookup.castAsLookup()); } public RegistryOps createSerializationContext(final DynamicOps parent) { return RegistryOps.create( parent, new RegistryOps.RegistryInfoLookup() { { Objects.requireNonNull(PlaceholderLookupProvider.this); } @Override public Optional> lookup(final ResourceKey> registryKey) { return PlaceholderLookupProvider.this.context .lookup(registryKey) .map(RegistryOps.RegistryInfo::fromRegistryLookup) .or( () -> Optional.of( new RegistryOps.RegistryInfo( PlaceholderLookupProvider.this.lookup.castAsOwner(), PlaceholderLookupProvider.this.lookup.castAsLookup(), Lifecycle.experimental() ) ) ); } } ); } public RegistryContextSwapper createSwapper() { return new RegistryContextSwapper() { { Objects.requireNonNull(PlaceholderLookupProvider.this); } @Override public DataResult swapTo(final Codec codec, final T value, final HolderLookup.Provider newContext) { return codec.encodeStart(PlaceholderLookupProvider.this.createSerializationContext(JavaOps.INSTANCE), value) .flatMap(v -> codec.parse(newContext.createSerializationContext(JavaOps.INSTANCE), v)); } }; } public boolean hasRegisteredPlaceholders() { return !this.holders.isEmpty() || !this.holderSets.isEmpty(); } private class UniversalLookup implements HolderGetter, HolderOwner { private UniversalLookup() { Objects.requireNonNull(PlaceholderLookupProvider.this); super(); } @Override public Optional> get(final ResourceKey id) { return Optional.of(this.getOrCreate(id)); } @Override public Holder.Reference getOrThrow(final ResourceKey id) { return this.getOrCreate(id); } private Holder.Reference getOrCreate(final ResourceKey id) { return (Holder.Reference)PlaceholderLookupProvider.this.holders.computeIfAbsent(id, k -> Holder.Reference.createStandAlone(this, k)); } @Override public Optional> get(final TagKey id) { return Optional.of(this.getOrCreate(id)); } @Override public HolderSet.Named getOrThrow(final TagKey id) { return this.getOrCreate(id); } private HolderSet.Named getOrCreate(final TagKey id) { return (HolderSet.Named)PlaceholderLookupProvider.this.holderSets.computeIfAbsent(id, k -> HolderSet.emptyNamed(this, k)); } public HolderGetter castAsLookup() { return this; } public HolderOwner castAsOwner() { return this; } } }