package net.minecraft.resources; import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import com.mojang.serialization.DynamicOps; import com.mojang.serialization.Lifecycle; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import net.minecraft.core.HolderGetter; import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderOwner; import net.minecraft.core.Registry; import net.minecraft.core.Holder.Reference; import net.minecraft.util.ExtraCodecs; public class RegistryOps extends DelegatingOps { private final RegistryOps.RegistryInfoLookup lookupProvider; public static RegistryOps create(DynamicOps delegate, HolderLookup.Provider registries) { return create(delegate, new RegistryOps.HolderLookupAdapter(registries)); } public static RegistryOps create(DynamicOps delegate, RegistryOps.RegistryInfoLookup lookupProvider) { return new RegistryOps<>(delegate, lookupProvider); } public static Dynamic injectRegistryContext(Dynamic dynamic, HolderLookup.Provider registries) { return new Dynamic<>(registries.createSerializationContext(dynamic.getOps()), dynamic.getValue()); } private RegistryOps(DynamicOps delegate, RegistryOps.RegistryInfoLookup lookupProvider) { super(delegate); this.lookupProvider = lookupProvider; } public RegistryOps withParent(DynamicOps ops) { return (RegistryOps)(ops == this.delegate ? this : new RegistryOps<>(ops, this.lookupProvider)); } public Optional> owner(ResourceKey> registryKey) { return this.lookupProvider.lookup(registryKey).map(RegistryOps.RegistryInfo::owner); } public Optional> getter(ResourceKey> registryKey) { return this.lookupProvider.lookup(registryKey).map(RegistryOps.RegistryInfo::getter); } public boolean equals(Object object) { if (this == object) { return true; } else if (object != null && this.getClass() == object.getClass()) { RegistryOps registryOps = (RegistryOps)object; return this.delegate.equals(registryOps.delegate) && this.lookupProvider.equals(registryOps.lookupProvider); } else { return false; } } public int hashCode() { return this.delegate.hashCode() * 31 + this.lookupProvider.hashCode(); } public static RecordCodecBuilder> retrieveGetter(ResourceKey> registryOps) { return ExtraCodecs.>retrieveContext( dynamicOps -> dynamicOps instanceof RegistryOps registryOpsx ? (DataResult)registryOpsx.lookupProvider .lookup(registryOps) .map(registryInfo -> DataResult.success(registryInfo.getter(), registryInfo.elementsLifecycle())) .orElseGet(() -> DataResult.error(() -> "Unknown registry: " + registryOps)) : DataResult.error(() -> "Not a registry ops") ) .forGetter(object -> null); } public static RecordCodecBuilder> retrieveElement(ResourceKey key) { ResourceKey> resourceKey = ResourceKey.createRegistryKey(key.registry()); return ExtraCodecs.>retrieveContext( dynamicOps -> dynamicOps instanceof RegistryOps registryOps ? (DataResult)registryOps.lookupProvider .lookup(resourceKey) .flatMap(registryInfo -> registryInfo.getter().get(key)) .map(DataResult::success) .orElseGet(() -> DataResult.error(() -> "Can't find value: " + key)) : DataResult.error(() -> "Not a registry ops") ) .forGetter(object -> null); } static final class HolderLookupAdapter implements RegistryOps.RegistryInfoLookup { private final HolderLookup.Provider lookupProvider; private final Map>, Optional>> lookups = new ConcurrentHashMap(); public HolderLookupAdapter(HolderLookup.Provider lookupProvider) { this.lookupProvider = lookupProvider; } @Override public Optional> lookup(ResourceKey> registryKey) { return (Optional>)this.lookups.computeIfAbsent(registryKey, this::createLookup); } private Optional> createLookup(ResourceKey> registryKey) { return this.lookupProvider.lookup(registryKey).map(RegistryOps.RegistryInfo::fromRegistryLookup); } public boolean equals(Object object) { return this == object ? true : object instanceof RegistryOps.HolderLookupAdapter holderLookupAdapter && this.lookupProvider.equals(holderLookupAdapter.lookupProvider); } public int hashCode() { return this.lookupProvider.hashCode(); } } public record RegistryInfo(HolderOwner owner, HolderGetter getter, Lifecycle elementsLifecycle) { public static RegistryOps.RegistryInfo fromRegistryLookup(HolderLookup.RegistryLookup registryLookup) { return new RegistryOps.RegistryInfo<>(registryLookup, registryLookup, registryLookup.registryLifecycle()); } } public interface RegistryInfoLookup { Optional> lookup(ResourceKey> registryKey); } }