package net.minecraft.server; import com.google.gson.JsonElement; import com.mojang.logging.LogUtils; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.stream.Stream; import net.minecraft.Util; import net.minecraft.core.HolderGetter; import net.minecraft.core.HolderLookup; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.core.MappedRegistry; import net.minecraft.core.RegistrationInfo; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.WritableRegistry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; import net.minecraft.tags.TagLoader; import net.minecraft.util.ProblemReporter; import net.minecraft.world.level.storage.loot.LootDataType; import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.ValidationContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import org.slf4j.Logger; public class ReloadableServerRegistries { private static final Logger LOGGER = LogUtils.getLogger(); private static final RegistrationInfo DEFAULT_REGISTRATION_INFO = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); public static CompletableFuture reload( LayeredRegistryAccess p_331894_, List> p_361834_, ResourceManager p_333753_, Executor p_334093_ ) { List> list = TagLoader.buildUpdatedLookups(p_331894_.getAccessForLoading(RegistryLayer.RELOADABLE), p_361834_); HolderLookup.Provider holderlookup$provider = HolderLookup.Provider.create(list.stream()); RegistryOps registryops = holderlookup$provider.createSerializationContext(JsonOps.INSTANCE); List>> list1 = LootDataType.values() .map(p_358525_ -> scheduleRegistryLoad((LootDataType)p_358525_, registryops, p_333753_, p_334093_)) .toList(); CompletableFuture>> completablefuture = Util.sequence(list1); return completablefuture.thenApplyAsync(p_358521_ -> createAndValidateFullContext(p_331894_, holderlookup$provider, (List>)p_358521_), p_334093_); } private static CompletableFuture> scheduleRegistryLoad( LootDataType p_335755_, RegistryOps p_328500_, ResourceManager p_330738_, Executor p_327700_ ) { return CompletableFuture.supplyAsync(() -> { WritableRegistry writableregistry = new MappedRegistry<>(p_335755_.registryKey(), Lifecycle.experimental()); Map map = new HashMap<>(); SimpleJsonResourceReloadListener.scanDirectory(p_330738_, p_335755_.registryKey(), p_328500_, p_335755_.codec(), map); map.forEach((p_332563_, p_332628_) -> writableregistry.register(ResourceKey.create(p_335755_.registryKey(), p_332563_), (T)p_332628_, DEFAULT_REGISTRATION_INFO)); TagLoader.loadTagsForRegistry(p_330738_, writableregistry); return writableregistry; }, p_327700_); } private static ReloadableServerRegistries.LoadResult createAndValidateFullContext( LayeredRegistryAccess p_368439_, HolderLookup.Provider p_370039_, List> p_363778_ ) { LayeredRegistryAccess layeredregistryaccess = createUpdatedRegistries(p_368439_, p_363778_); HolderLookup.Provider holderlookup$provider = concatenateLookups(p_370039_, layeredregistryaccess.getLayer(RegistryLayer.RELOADABLE)); validateLootRegistries(holderlookup$provider); return new ReloadableServerRegistries.LoadResult(layeredregistryaccess, holderlookup$provider); } private static HolderLookup.Provider concatenateLookups(HolderLookup.Provider p_366421_, HolderLookup.Provider p_368061_) { return HolderLookup.Provider.create(Stream.concat(p_366421_.listRegistries(), p_368061_.listRegistries())); } private static void validateLootRegistries(HolderLookup.Provider p_368763_) { ProblemReporter.Collector problemreporter$collector = new ProblemReporter.Collector(); ValidationContext validationcontext = new ValidationContext(problemreporter$collector, LootContextParamSets.ALL_PARAMS, p_368763_); LootDataType.values().forEach(p_358528_ -> validateRegistry(validationcontext, (LootDataType)p_358528_, p_368763_)); problemreporter$collector.get() .forEach((p_336191_, p_332871_) -> LOGGER.warn("Found loot table element validation problem in {}: {}", p_336191_, p_332871_)); } private static LayeredRegistryAccess createUpdatedRegistries(LayeredRegistryAccess p_334470_, List> p_328349_) { return p_334470_.replaceFrom(RegistryLayer.RELOADABLE, new RegistryAccess.ImmutableRegistryAccess(p_328349_).freeze()); } private static void validateRegistry(ValidationContext p_335560_, LootDataType p_335486_, HolderLookup.Provider p_365047_) { HolderLookup holderlookup = p_365047_.lookupOrThrow(p_335486_.registryKey()); holderlookup.listElements().forEach(p_334560_ -> p_335486_.runValidation(p_335560_, p_334560_.key(), p_334560_.value())); } public static class Holder { private final HolderLookup.Provider registries; public Holder(HolderLookup.Provider p_369437_) { this.registries = p_369437_; } public HolderGetter.Provider lookup() { return this.registries; } public Collection getKeys(ResourceKey> p_328291_) { return this.registries.lookupOrThrow(p_328291_).listElementIds().map(ResourceKey::location).toList(); } public LootTable getLootTable(ResourceKey p_331432_) { return this.registries .lookup(Registries.LOOT_TABLE) .flatMap(p_328118_ -> p_328118_.get(p_331432_)) .map(net.minecraft.core.Holder::value) .orElse(LootTable.EMPTY); } } public static record LoadResult(LayeredRegistryAccess layers, HolderLookup.Provider lookupWithUpdatedTags) { } }