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.Optional; 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.core.Holder.Reference; import net.minecraft.core.HolderSet.Named; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; public class PlaceholderLookupProvider implements HolderGetter.Provider { final HolderLookup.Provider context; final PlaceholderLookupProvider.UniversalLookup lookup = new PlaceholderLookupProvider.UniversalLookup(); final Map, Reference> holders = new HashMap(); final Map, Named> holderSets = new HashMap(); public PlaceholderLookupProvider(HolderLookup.Provider context) { this.context = context; } @Override public Optional> lookup(ResourceKey> registryKey) { return Optional.of(this.lookup.castAsLookup()); } public RegistryOps createSerializationContext(DynamicOps ops) { return RegistryOps.create( ops, new RegistryOps.RegistryInfoLookup() { @Override public Optional> lookup(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() { @Override public DataResult swapTo(Codec codec, T value, HolderLookup.Provider provider) { return codec.encodeStart(PlaceholderLookupProvider.this.createSerializationContext(JavaOps.INSTANCE), value) .flatMap(object -> codec.parse(provider.createSerializationContext(JavaOps.INSTANCE), object)); } }; } public boolean hasRegisteredPlaceholders() { return !this.holders.isEmpty() || !this.holderSets.isEmpty(); } class UniversalLookup implements HolderGetter, HolderOwner { @Override public Optional> get(ResourceKey resourceKey) { return Optional.of(this.getOrCreate(resourceKey)); } @Override public Reference getOrThrow(ResourceKey resourceKey) { return this.getOrCreate(resourceKey); } private Reference getOrCreate(ResourceKey key) { return (Reference)PlaceholderLookupProvider.this.holders.computeIfAbsent(key, resourceKey -> Reference.createStandAlone(this, resourceKey)); } @Override public Optional> get(TagKey tagKey) { return Optional.of(this.getOrCreate(tagKey)); } @Override public Named getOrThrow(TagKey tagKey) { return this.getOrCreate(tagKey); } private Named getOrCreate(TagKey key) { return (Named)PlaceholderLookupProvider.this.holderSets.computeIfAbsent(key, tagKey -> HolderSet.emptyNamed(this, tagKey)); } public HolderGetter castAsLookup() { return this; } public HolderOwner castAsOwner() { return this; } } }