package net.minecraft.core; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Lifecycle; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; import net.minecraft.data.worldgen.BootstrapContext; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import org.apache.commons.lang3.mutable.MutableObject; public class RegistrySetBuilder { private final List> entries = new ArrayList<>(); static HolderGetter wrapContextLookup(final HolderLookup.RegistryLookup p_255625_) { return new RegistrySetBuilder.EmptyTagLookup(p_255625_) { @Override public Optional> get(ResourceKey p_255765_) { return p_255625_.get(p_255765_); } }; } static HolderLookup.RegistryLookup lookupFromMap( final ResourceKey> p_311196_, final Lifecycle p_311352_, HolderOwner p_335968_, final Map, Holder.Reference> p_311458_ ) { return new RegistrySetBuilder.EmptyTagRegistryLookup(p_335968_) { @Override public ResourceKey> key() { return p_311196_; } @Override public Lifecycle registryLifecycle() { return p_311352_; } @Override public Optional> get(ResourceKey p_310975_) { return Optional.ofNullable(p_311458_.get(p_310975_)); } @Override public Stream> listElements() { return p_311458_.values().stream(); } }; } public RegistrySetBuilder add( ResourceKey> p_256446_, Lifecycle p_256394_, RegistrySetBuilder.RegistryBootstrap p_256638_ ) { this.entries.add(new RegistrySetBuilder.RegistryStub<>(p_256446_, p_256394_, p_256638_)); return this; } public RegistrySetBuilder add(ResourceKey> p_256261_, RegistrySetBuilder.RegistryBootstrap p_256010_) { return this.add(p_256261_, Lifecycle.stable(), p_256010_); } private RegistrySetBuilder.BuildState createState(RegistryAccess p_256400_) { RegistrySetBuilder.BuildState registrysetbuilder$buildstate = RegistrySetBuilder.BuildState.create( p_256400_, this.entries.stream().map(RegistrySetBuilder.RegistryStub::key) ); this.entries.forEach(p_255629_ -> p_255629_.apply(registrysetbuilder$buildstate)); return registrysetbuilder$buildstate; } private static HolderLookup.Provider buildProviderWithContext( RegistrySetBuilder.UniversalOwner p_328219_, RegistryAccess p_311176_, Stream> p_311668_ ) { record Entry(HolderLookup.RegistryLookup lookup, RegistryOps.RegistryInfo opsInfo) { public static Entry createForContextRegistry(HolderLookup.RegistryLookup p_332859_) { return new Entry<>(new RegistrySetBuilder.EmptyTagLookupWrapper<>(p_332859_, p_332859_), RegistryOps.RegistryInfo.fromRegistryLookup(p_332859_)); } public static Entry createForNewRegistry(RegistrySetBuilder.UniversalOwner p_329338_, HolderLookup.RegistryLookup p_334381_) { return new Entry<>( new RegistrySetBuilder.EmptyTagLookupWrapper<>(p_329338_.cast(), p_334381_), new RegistryOps.RegistryInfo<>(p_329338_.cast(), p_334381_, p_334381_.registryLifecycle()) ); } } final Map>, Entry> map = new HashMap<>(); p_311176_.registries().forEach(p_358096_ -> map.put(p_358096_.key(), Entry.createForContextRegistry(p_358096_.value()))); p_311668_.forEach(p_325692_ -> map.put(p_325692_.key(), Entry.createForNewRegistry(p_328219_, p_325692_))); return new HolderLookup.Provider() { @Override public Stream>> listRegistryKeys() { return map.keySet().stream(); } Optional> getEntry(ResourceKey> p_332279_) { return Optional.ofNullable((Entry)map.get(p_332279_)); } @Override public Optional> lookup(ResourceKey> p_328757_) { return this.getEntry(p_328757_).map(Entry::lookup); } @Override public RegistryOps createSerializationContext(DynamicOps p_334886_) { return RegistryOps.create(p_334886_, new RegistryOps.RegistryInfoLookup() { @Override public Optional> lookup(ResourceKey> p_331561_) { return getEntry(p_331561_).map(Entry::opsInfo); } }); } }; } public HolderLookup.Provider build(RegistryAccess p_256112_) { RegistrySetBuilder.BuildState registrysetbuilder$buildstate = this.createState(p_256112_); Stream> stream = this.entries .stream() .map(p_325689_ -> p_325689_.collectRegisteredValues(registrysetbuilder$buildstate).buildAsLookup(registrysetbuilder$buildstate.owner)); HolderLookup.Provider holderlookup$provider = buildProviderWithContext(registrysetbuilder$buildstate.owner, p_256112_, stream); registrysetbuilder$buildstate.reportNotCollectedHolders(); registrysetbuilder$buildstate.reportUnclaimedRegisteredValues(); registrysetbuilder$buildstate.throwOnError(); return holderlookup$provider; } private HolderLookup.Provider createLazyFullPatchedRegistries( RegistryAccess p_312999_, HolderLookup.Provider p_309815_, Cloner.Factory p_311992_, Map>, RegistrySetBuilder.RegistryContents> p_309672_, HolderLookup.Provider p_312434_ ) { RegistrySetBuilder.UniversalOwner registrysetbuilder$universalowner = new RegistrySetBuilder.UniversalOwner(); MutableObject mutableobject = new MutableObject<>(); List> list = p_309672_.keySet() .stream() .map( p_308443_ -> this.createLazyFullPatchedRegistries( registrysetbuilder$universalowner, p_311992_, (ResourceKey>)p_308443_, p_312434_, p_309815_, mutableobject ) ) .collect(Collectors.toUnmodifiableList()); HolderLookup.Provider holderlookup$provider = buildProviderWithContext(registrysetbuilder$universalowner, p_312999_, list.stream()); mutableobject.setValue(holderlookup$provider); return holderlookup$provider; } private HolderLookup.RegistryLookup createLazyFullPatchedRegistries( HolderOwner p_312548_, Cloner.Factory p_312934_, ResourceKey> p_313093_, HolderLookup.Provider p_311682_, HolderLookup.Provider p_313198_, MutableObject p_311605_ ) { Cloner cloner = p_312934_.cloner(p_313093_); if (cloner == null) { throw new NullPointerException("No cloner for " + p_313093_.location()); } else { Map, Holder.Reference> map = new HashMap<>(); HolderLookup.RegistryLookup registrylookup = p_311682_.lookupOrThrow(p_313093_); registrylookup.listElements().forEach(p_308453_ -> { ResourceKey resourcekey = p_308453_.key(); RegistrySetBuilder.LazyHolder lazyholder = new RegistrySetBuilder.LazyHolder<>(p_312548_, resourcekey); lazyholder.supplier = () -> cloner.clone((T)p_308453_.value(), p_311682_, p_311605_.getValue()); map.put(resourcekey, lazyholder); }); HolderLookup.RegistryLookup registrylookup1 = p_313198_.lookupOrThrow(p_313093_); registrylookup1.listElements().forEach(p_308430_ -> { ResourceKey resourcekey = p_308430_.key(); map.computeIfAbsent(resourcekey, p_308437_ -> { RegistrySetBuilder.LazyHolder lazyholder = new RegistrySetBuilder.LazyHolder<>(p_312548_, resourcekey); lazyholder.supplier = () -> cloner.clone((T)p_308430_.value(), p_313198_, p_311605_.getValue()); return lazyholder; }); }); Lifecycle lifecycle = registrylookup.registryLifecycle().add(registrylookup1.registryLifecycle()); return lookupFromMap(p_313093_, lifecycle, p_312548_, map); } } public RegistrySetBuilder.PatchedRegistries buildPatch(RegistryAccess p_255676_, HolderLookup.Provider p_255900_, Cloner.Factory p_310265_) { RegistrySetBuilder.BuildState registrysetbuilder$buildstate = this.createState(p_255676_); Map>, RegistrySetBuilder.RegistryContents> map = new HashMap<>(); this.entries .stream() .map(p_308447_ -> p_308447_.collectRegisteredValues(registrysetbuilder$buildstate)) .forEach(p_272339_ -> map.put(p_272339_.key, (RegistrySetBuilder.RegistryContents)p_272339_)); Set>> set = p_255676_.listRegistryKeys().collect(Collectors.toUnmodifiableSet()); p_255900_.listRegistryKeys() .filter(p_308455_ -> !set.contains(p_308455_)) .forEach( p_308463_ -> map.putIfAbsent( (ResourceKey>)p_308463_, new RegistrySetBuilder.RegistryContents<>((ResourceKey>)p_308463_, Lifecycle.stable(), Map.of()) ) ); Stream> stream = map.values().stream().map(p_325694_ -> p_325694_.buildAsLookup(registrysetbuilder$buildstate.owner)); HolderLookup.Provider holderlookup$provider = buildProviderWithContext(registrysetbuilder$buildstate.owner, p_255676_, stream); registrysetbuilder$buildstate.reportUnclaimedRegisteredValues(); registrysetbuilder$buildstate.throwOnError(); HolderLookup.Provider holderlookup$provider1 = this.createLazyFullPatchedRegistries(p_255676_, p_255900_, p_310265_, map, holderlookup$provider); return new RegistrySetBuilder.PatchedRegistries(holderlookup$provider1, holderlookup$provider); } record BuildState( RegistrySetBuilder.UniversalOwner owner, RegistrySetBuilder.UniversalLookup lookup, Map> registries, Map, RegistrySetBuilder.RegisteredValue> registeredValues, List errors ) { public static RegistrySetBuilder.BuildState create(RegistryAccess p_255995_, Stream>> p_256495_) { RegistrySetBuilder.UniversalOwner registrysetbuilder$universalowner = new RegistrySetBuilder.UniversalOwner(); List list = new ArrayList<>(); RegistrySetBuilder.UniversalLookup registrysetbuilder$universallookup = new RegistrySetBuilder.UniversalLookup(registrysetbuilder$universalowner); Builder> builder = ImmutableMap.builder(); p_255995_.registries().forEach(p_358098_ -> builder.put(p_358098_.key().location(), RegistrySetBuilder.wrapContextLookup(p_358098_.value()))); p_256495_.forEach(p_256603_ -> builder.put(p_256603_.location(), registrysetbuilder$universallookup)); return new RegistrySetBuilder.BuildState( registrysetbuilder$universalowner, registrysetbuilder$universallookup, builder.build(), new HashMap<>(), list ); } public BootstrapContext bootstrapContext() { return new BootstrapContext() { @Override public Holder.Reference register(ResourceKey p_256176_, T p_256422_, Lifecycle p_255924_) { RegistrySetBuilder.RegisteredValue registeredvalue = BuildState.this.registeredValues .put(p_256176_, new RegistrySetBuilder.RegisteredValue(p_256422_, p_255924_)); if (registeredvalue != null) { BuildState.this.errors .add( new IllegalStateException( "Duplicate registration for " + p_256176_ + ", new=" + p_256422_ + ", old=" + registeredvalue.value ) ); } return BuildState.this.lookup.getOrCreate(p_256176_); } @Override public HolderGetter lookup(ResourceKey> p_255961_) { return (HolderGetter)BuildState.this.registries.getOrDefault(p_255961_.location(), BuildState.this.lookup); } }; } public void reportUnclaimedRegisteredValues() { this.registeredValues .forEach( (p_325695_, p_325696_) -> this.errors.add(new IllegalStateException("Orpaned value " + p_325696_.value + " for key " + p_325695_)) ); } public void reportNotCollectedHolders() { for (ResourceKey resourcekey : this.lookup.holders.keySet()) { this.errors.add(new IllegalStateException("Unreferenced key: " + resourcekey)); } } public void throwOnError() { if (!this.errors.isEmpty()) { IllegalStateException illegalstateexception = new IllegalStateException("Errors during registry creation"); for (RuntimeException runtimeexception : this.errors) { illegalstateexception.addSuppressed(runtimeexception); } throw illegalstateexception; } } } abstract static class EmptyTagLookup implements HolderGetter { protected final HolderOwner owner; protected EmptyTagLookup(HolderOwner p_256166_) { this.owner = p_256166_; } @Override public Optional> get(TagKey p_256664_) { return Optional.of(HolderSet.emptyNamed(this.owner, p_256664_)); } } static class EmptyTagLookupWrapper extends RegistrySetBuilder.EmptyTagRegistryLookup implements HolderLookup.RegistryLookup.Delegate { private final HolderLookup.RegistryLookup parent; EmptyTagLookupWrapper(HolderOwner p_327736_, HolderLookup.RegistryLookup p_328715_) { super(p_327736_); this.parent = p_328715_; } @Override public HolderLookup.RegistryLookup parent() { return this.parent; } } abstract static class EmptyTagRegistryLookup extends RegistrySetBuilder.EmptyTagLookup implements HolderLookup.RegistryLookup { protected EmptyTagRegistryLookup(HolderOwner p_334522_) { super(p_334522_); } @Override public Stream> listTags() { throw new UnsupportedOperationException("Tags are not available in datagen"); } } static class LazyHolder extends Holder.Reference { @Nullable Supplier supplier; protected LazyHolder(HolderOwner p_311720_, @Nullable ResourceKey p_312254_) { super(Holder.Reference.Type.STAND_ALONE, p_311720_, p_312254_, null); } @Override protected void bindValue(T p_309503_) { super.bindValue(p_309503_); this.supplier = null; } @Override public T value() { if (this.supplier != null) { this.bindValue(this.supplier.get()); } return super.value(); } } public record PatchedRegistries(HolderLookup.Provider full, HolderLookup.Provider patches) { } record RegisteredValue(T value, Lifecycle lifecycle) { } @FunctionalInterface public interface RegistryBootstrap { void run(BootstrapContext p_331285_); } record RegistryContents( ResourceKey> key, Lifecycle lifecycle, Map, RegistrySetBuilder.ValueAndHolder> values ) { public HolderLookup.RegistryLookup buildAsLookup(RegistrySetBuilder.UniversalOwner p_333021_) { Map, Holder.Reference> map = this.values .entrySet() .stream() .collect( Collectors.toUnmodifiableMap( java.util.Map.Entry::getKey, p_311794_ -> { RegistrySetBuilder.ValueAndHolder valueandholder = p_311794_.getValue(); Holder.Reference reference = valueandholder.holder() .orElseGet(() -> Holder.Reference.createStandAlone(p_333021_.cast(), p_311794_.getKey())); reference.bindValue(valueandholder.value().value()); return reference; } ) ); return RegistrySetBuilder.lookupFromMap(this.key, this.lifecycle, p_333021_.cast(), map); } } record RegistryStub(ResourceKey> key, Lifecycle lifecycle, RegistrySetBuilder.RegistryBootstrap bootstrap) { void apply(RegistrySetBuilder.BuildState p_256272_) { this.bootstrap.run(p_256272_.bootstrapContext()); } public RegistrySetBuilder.RegistryContents collectRegisteredValues(RegistrySetBuilder.BuildState p_256416_) { Map, RegistrySetBuilder.ValueAndHolder> map = new HashMap<>(); Iterator, RegistrySetBuilder.RegisteredValue>> iterator = p_256416_.registeredValues.entrySet().iterator(); while (iterator.hasNext()) { java.util.Map.Entry, RegistrySetBuilder.RegisteredValue> entry = iterator.next(); ResourceKey resourcekey = entry.getKey(); if (resourcekey.isFor(this.key)) { RegistrySetBuilder.RegisteredValue registeredvalue = (RegistrySetBuilder.RegisteredValue)entry.getValue(); Holder.Reference reference = (Holder.Reference)p_256416_.lookup.holders.remove(resourcekey); map.put((ResourceKey)resourcekey, new RegistrySetBuilder.ValueAndHolder<>(registeredvalue, Optional.ofNullable(reference))); iterator.remove(); } } return new RegistrySetBuilder.RegistryContents<>(this.key, this.lifecycle, map); } } static class UniversalLookup extends RegistrySetBuilder.EmptyTagLookup { final Map, Holder.Reference> holders = new HashMap<>(); public UniversalLookup(HolderOwner p_256629_) { super(p_256629_); } @Override public Optional> get(ResourceKey p_256303_) { return Optional.of(this.getOrCreate(p_256303_)); } Holder.Reference getOrCreate(ResourceKey p_256298_) { return (Holder.Reference)((Map)this.holders) .computeIfAbsent(p_256298_, p_256154_ -> Holder.Reference.createStandAlone(this.owner, (ResourceKey)p_256154_)); } } static class UniversalOwner implements HolderOwner { public HolderOwner cast() { return (HolderOwner)this; } } record ValueAndHolder(RegistrySetBuilder.RegisteredValue value, Optional> holder) { } }