package net.minecraft.core; import com.google.common.collect.ImmutableMap; import com.mojang.logging.LogUtils; import com.mojang.serialization.Lifecycle; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Map.Entry; import java.util.stream.Collectors; import java.util.stream.Stream; import net.minecraft.resources.ResourceKey; import org.slf4j.Logger; /** * The root level registry, essentially a registry of registries. It is also an access point, hence the name, for other dynamic registries. */ public interface RegistryAccess extends HolderLookup.Provider { Logger LOGGER = LogUtils.getLogger(); RegistryAccess.Frozen EMPTY = new RegistryAccess.ImmutableRegistryAccess(Map.of()).freeze(); /** * Get the registry owned by this registry access by the given key. If it doesn't exist, the default registry of registries is queried instead, which contains static registries such as blocks. * The returned registry can not guarantee that it is writable here, so the return type is widened to {@code Registry} instead. */ Optional> registry(ResourceKey> registryKey); @Override default Optional> lookup(ResourceKey> registryKey) { return this.registry(registryKey).map(Registry::asLookup); } /** * A variant of {@link #registry(ResourceKey)} that throws if the registry does not exist. */ default Registry registryOrThrow(ResourceKey> registryKey) { return (Registry)this.registry(registryKey).orElseThrow(() -> new IllegalStateException("Missing registry: " + registryKey)); } Stream> registries(); @Override default Stream>> listRegistries() { return this.registries().map(RegistryAccess.RegistryEntry::key); } static RegistryAccess.Frozen fromRegistryOfRegistries(Registry> registryOfRegistries) { return new RegistryAccess.Frozen() { @Override public Optional> registry(ResourceKey> registryKey) { Registry> registry = (Registry>)registryOfRegistries; return registry.getOptional((ResourceKey>)registryKey); } @Override public Stream> registries() { return registryOfRegistries.entrySet().stream().map(RegistryAccess.RegistryEntry::fromMapEntry); } @Override public RegistryAccess.Frozen freeze() { return this; } }; } default RegistryAccess.Frozen freeze() { class FrozenAccess extends RegistryAccess.ImmutableRegistryAccess implements RegistryAccess.Frozen { protected FrozenAccess(final Stream> registries) { super(registries); } } return new FrozenAccess(this.registries().map(RegistryAccess.RegistryEntry::freeze)); } default Lifecycle allRegistriesLifecycle() { return (Lifecycle)this.registries().map(registryEntry -> registryEntry.value.registryLifecycle()).reduce(Lifecycle.stable(), Lifecycle::add); } public interface Frozen extends RegistryAccess { } public static class ImmutableRegistryAccess implements RegistryAccess { private final Map>, ? extends Registry> registries; public ImmutableRegistryAccess(List> registries) { this.registries = (Map>, ? extends Registry>)registries.stream() .collect(Collectors.toUnmodifiableMap(Registry::key, registry -> registry)); } public ImmutableRegistryAccess(Map>, ? extends Registry> registries) { this.registries = Map.copyOf(registries); } public ImmutableRegistryAccess(Stream> registries) { this.registries = (Map>, ? extends Registry>)registries.collect( ImmutableMap.toImmutableMap(RegistryAccess.RegistryEntry::key, RegistryAccess.RegistryEntry::value) ); } @Override public Optional> registry(ResourceKey> registryKey) { return Optional.ofNullable((Registry)this.registries.get(registryKey)).map(registry -> registry); } @Override public Stream> registries() { return this.registries.entrySet().stream().map(RegistryAccess.RegistryEntry::fromMapEntry); } } public record RegistryEntry(ResourceKey> key, Registry value) { private static > RegistryAccess.RegistryEntry fromMapEntry( Entry>, R> mapEntry ) { return fromUntyped((ResourceKey>)mapEntry.getKey(), (Registry)mapEntry.getValue()); } private static RegistryAccess.RegistryEntry fromUntyped(ResourceKey> key, Registry value) { return new RegistryAccess.RegistryEntry<>((ResourceKey>)key, (Registry)value); } private RegistryAccess.RegistryEntry freeze() { return new RegistryAccess.RegistryEntry<>(this.key, this.value.freeze()); } } }