/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.gson.JsonElement * com.mojang.logging.LogUtils * com.mojang.serialization.Codec * com.mojang.serialization.DataResult * com.mojang.serialization.Decoder * com.mojang.serialization.JsonOps * com.mojang.serialization.Lifecycle * org.slf4j.Logger */ package net.minecraft.resources; import com.google.gson.JsonElement; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.Decoder; import com.mojang.serialization.JsonOps; import com.mojang.serialization.Lifecycle; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.stream.Collectors; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; import net.minecraft.core.HolderLookup; import net.minecraft.core.MappedRegistry; import net.minecraft.core.RegistrationInfo; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistrySynchronization; import net.minecraft.core.WritableRegistry; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.GameTestInstance; import net.minecraft.gametest.framework.TestEnvironmentDefinition; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.ChatType; import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.Identifier; import net.minecraft.resources.RegistryOps; import net.minecraft.resources.ResourceKey; import net.minecraft.server.dialog.Dialog; import net.minecraft.server.packs.repository.KnownPack; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceProvider; import net.minecraft.tags.TagLoader; import net.minecraft.tags.TagNetworkSerialization; import net.minecraft.util.StrictJsonParser; import net.minecraft.util.Util; import net.minecraft.world.damagesource.DamageType; import net.minecraft.world.entity.animal.CatVariant; import net.minecraft.world.entity.animal.ChickenVariant; import net.minecraft.world.entity.animal.CowVariant; import net.minecraft.world.entity.animal.PigVariant; import net.minecraft.world.entity.animal.ZombieNautilusVariant; import net.minecraft.world.entity.animal.frog.FrogVariant; import net.minecraft.world.entity.animal.wolf.WolfSoundVariant; import net.minecraft.world.entity.animal.wolf.WolfVariant; import net.minecraft.world.entity.decoration.PaintingVariant; import net.minecraft.world.item.Instrument; import net.minecraft.world.item.JukeboxSong; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.providers.EnchantmentProvider; import net.minecraft.world.item.equipment.trim.TrimMaterial; import net.minecraft.world.item.equipment.trim.TrimPattern; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.MultiNoiseBiomeSourceParameterList; import net.minecraft.world.level.block.entity.BannerPattern; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.DensityFunction; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorPreset; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraft.world.level.levelgen.presets.WorldPreset; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureSet; import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType; import net.minecraft.world.level.levelgen.synth.NormalNoise; import net.minecraft.world.timeline.Timeline; import org.slf4j.Logger; public class RegistryDataLoader { private static final Logger LOGGER = LogUtils.getLogger(); private static final Comparator> ERROR_KEY_COMPARATOR = Comparator.comparing(ResourceKey::registry).thenComparing(ResourceKey::identifier); private static final RegistrationInfo NETWORK_REGISTRATION_INFO = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); private static final Function, RegistrationInfo> REGISTRATION_INFO_CACHE = Util.memoize(knownPack -> { Lifecycle lifecycle = knownPack.map(KnownPack::isVanilla).map(info -> Lifecycle.stable()).orElse(Lifecycle.experimental()); return new RegistrationInfo((Optional)knownPack, lifecycle); }); public static final List> WORLDGEN_REGISTRIES = List.of(new RegistryData(Registries.DIMENSION_TYPE, DimensionType.DIRECT_CODEC), new RegistryData(Registries.BIOME, Biome.DIRECT_CODEC), new RegistryData(Registries.CHAT_TYPE, ChatType.DIRECT_CODEC), new RegistryData(Registries.CONFIGURED_CARVER, ConfiguredWorldCarver.DIRECT_CODEC), new RegistryData(Registries.CONFIGURED_FEATURE, ConfiguredFeature.DIRECT_CODEC), new RegistryData(Registries.PLACED_FEATURE, PlacedFeature.DIRECT_CODEC), new RegistryData(Registries.STRUCTURE, Structure.DIRECT_CODEC), new RegistryData(Registries.STRUCTURE_SET, StructureSet.DIRECT_CODEC), new RegistryData(Registries.PROCESSOR_LIST, StructureProcessorType.DIRECT_CODEC), new RegistryData(Registries.TEMPLATE_POOL, StructureTemplatePool.DIRECT_CODEC), new RegistryData(Registries.NOISE_SETTINGS, NoiseGeneratorSettings.DIRECT_CODEC), new RegistryData(Registries.NOISE, NormalNoise.NoiseParameters.DIRECT_CODEC), new RegistryData(Registries.DENSITY_FUNCTION, DensityFunction.DIRECT_CODEC), new RegistryData(Registries.WORLD_PRESET, WorldPreset.DIRECT_CODEC), new RegistryData(Registries.FLAT_LEVEL_GENERATOR_PRESET, FlatLevelGeneratorPreset.DIRECT_CODEC), new RegistryData(Registries.TRIM_PATTERN, TrimPattern.DIRECT_CODEC), new RegistryData(Registries.TRIM_MATERIAL, TrimMaterial.DIRECT_CODEC), new RegistryData(Registries.TRIAL_SPAWNER_CONFIG, TrialSpawnerConfig.DIRECT_CODEC), new RegistryData(Registries.WOLF_VARIANT, WolfVariant.DIRECT_CODEC, true), new RegistryData(Registries.WOLF_SOUND_VARIANT, WolfSoundVariant.DIRECT_CODEC, true), new RegistryData(Registries.PIG_VARIANT, PigVariant.DIRECT_CODEC, true), new RegistryData(Registries.FROG_VARIANT, FrogVariant.DIRECT_CODEC, true), new RegistryData(Registries.CAT_VARIANT, CatVariant.DIRECT_CODEC, true), new RegistryData(Registries.COW_VARIANT, CowVariant.DIRECT_CODEC, true), new RegistryData(Registries.CHICKEN_VARIANT, ChickenVariant.DIRECT_CODEC, true), new RegistryData(Registries.ZOMBIE_NAUTILUS_VARIANT, ZombieNautilusVariant.DIRECT_CODEC, true), new RegistryData(Registries.PAINTING_VARIANT, PaintingVariant.DIRECT_CODEC, true), new RegistryData(Registries.DAMAGE_TYPE, DamageType.DIRECT_CODEC), new RegistryData(Registries.MULTI_NOISE_BIOME_SOURCE_PARAMETER_LIST, MultiNoiseBiomeSourceParameterList.DIRECT_CODEC), new RegistryData(Registries.BANNER_PATTERN, BannerPattern.DIRECT_CODEC), new RegistryData(Registries.ENCHANTMENT, Enchantment.DIRECT_CODEC), new RegistryData(Registries.ENCHANTMENT_PROVIDER, EnchantmentProvider.DIRECT_CODEC), new RegistryData(Registries.JUKEBOX_SONG, JukeboxSong.DIRECT_CODEC), new RegistryData(Registries.INSTRUMENT, Instrument.DIRECT_CODEC), new RegistryData(Registries.TEST_ENVIRONMENT, TestEnvironmentDefinition.DIRECT_CODEC), new RegistryData(Registries.TEST_INSTANCE, GameTestInstance.DIRECT_CODEC), new RegistryData(Registries.DIALOG, Dialog.DIRECT_CODEC), new RegistryData(Registries.TIMELINE, Timeline.DIRECT_CODEC)); public static final List> DIMENSION_REGISTRIES = List.of(new RegistryData(Registries.LEVEL_STEM, LevelStem.CODEC)); public static final List> SYNCHRONIZED_REGISTRIES = List.of(new RegistryData(Registries.BIOME, Biome.NETWORK_CODEC), new RegistryData(Registries.CHAT_TYPE, ChatType.DIRECT_CODEC), new RegistryData(Registries.TRIM_PATTERN, TrimPattern.DIRECT_CODEC), new RegistryData(Registries.TRIM_MATERIAL, TrimMaterial.DIRECT_CODEC), new RegistryData(Registries.WOLF_VARIANT, WolfVariant.NETWORK_CODEC, true), new RegistryData(Registries.WOLF_SOUND_VARIANT, WolfSoundVariant.NETWORK_CODEC, true), new RegistryData(Registries.PIG_VARIANT, PigVariant.NETWORK_CODEC, true), new RegistryData(Registries.FROG_VARIANT, FrogVariant.NETWORK_CODEC, true), new RegistryData(Registries.CAT_VARIANT, CatVariant.NETWORK_CODEC, true), new RegistryData(Registries.COW_VARIANT, CowVariant.NETWORK_CODEC, true), new RegistryData(Registries.CHICKEN_VARIANT, ChickenVariant.NETWORK_CODEC, true), new RegistryData(Registries.ZOMBIE_NAUTILUS_VARIANT, ZombieNautilusVariant.NETWORK_CODEC, true), new RegistryData(Registries.PAINTING_VARIANT, PaintingVariant.DIRECT_CODEC, true), new RegistryData(Registries.DIMENSION_TYPE, DimensionType.NETWORK_CODEC), new RegistryData(Registries.DAMAGE_TYPE, DamageType.DIRECT_CODEC), new RegistryData(Registries.BANNER_PATTERN, BannerPattern.DIRECT_CODEC), new RegistryData(Registries.ENCHANTMENT, Enchantment.DIRECT_CODEC), new RegistryData(Registries.JUKEBOX_SONG, JukeboxSong.DIRECT_CODEC), new RegistryData(Registries.INSTRUMENT, Instrument.DIRECT_CODEC), new RegistryData(Registries.TEST_ENVIRONMENT, TestEnvironmentDefinition.DIRECT_CODEC), new RegistryData(Registries.TEST_INSTANCE, GameTestInstance.DIRECT_CODEC), new RegistryData(Registries.DIALOG, Dialog.DIRECT_CODEC), new RegistryData(Registries.TIMELINE, Timeline.NETWORK_CODEC)); public static RegistryAccess.Frozen load(ResourceManager resourceManager, List> contextRegistries, List> registriesToLoad) { return RegistryDataLoader.load((Loader loader, RegistryOps.RegistryInfoLookup context) -> loader.loadFromResources(resourceManager, context), contextRegistries, registriesToLoad); } public static RegistryAccess.Frozen load(Map>, NetworkedRegistryData> entries, ResourceProvider knownDataSource, List> contextRegistries, List> registriesToLoad) { return RegistryDataLoader.load((Loader loader, RegistryOps.RegistryInfoLookup context) -> loader.loadFromNetwork(entries, knownDataSource, context), contextRegistries, registriesToLoad); } private static RegistryAccess.Frozen load(LoadingFunction loadingFunction, List> contextRegistries, List> registriesToLoad) { HashMap loadingErrors = new HashMap(); List> newRegistriesAndLoaders = registriesToLoad.stream().map(r -> r.create(Lifecycle.stable(), loadingErrors)).collect(Collectors.toUnmodifiableList()); RegistryOps.RegistryInfoLookup contextAndNewRegistries = RegistryDataLoader.createContext(contextRegistries, newRegistriesAndLoaders); newRegistriesAndLoaders.forEach(loader -> loadingFunction.apply((Loader)loader, contextAndNewRegistries)); newRegistriesAndLoaders.forEach(p -> { WritableRegistry registry = p.registry(); try { registry.freeze(); } catch (Exception e) { loadingErrors.put(registry.key(), e); } if (p.data.requiredNonEmpty && registry.size() == 0) { loadingErrors.put(registry.key(), new IllegalStateException("Registry must be non-empty: " + String.valueOf(registry.key().identifier()))); } }); if (!loadingErrors.isEmpty()) { throw RegistryDataLoader.logErrors(loadingErrors); } return new RegistryAccess.ImmutableRegistryAccess(newRegistriesAndLoaders.stream().map(Loader::registry).toList()).freeze(); } private static RegistryOps.RegistryInfoLookup createContext(List> contextRegistries, List> newRegistriesAndLoaders) { final HashMap result = new HashMap(); contextRegistries.forEach(e -> result.put(e.key(), RegistryDataLoader.createInfoForContextRegistry(e))); newRegistriesAndLoaders.forEach(e -> result.put(e.registry.key(), RegistryDataLoader.createInfoForNewRegistry(e.registry))); return new RegistryOps.RegistryInfoLookup(){ @Override public Optional> lookup(ResourceKey> key) { return Optional.ofNullable((RegistryOps.RegistryInfo)result.get(key)); } }; } private static RegistryOps.RegistryInfo createInfoForNewRegistry(WritableRegistry e) { return new RegistryOps.RegistryInfo(e, e.createRegistrationLookup(), e.registryLifecycle()); } private static RegistryOps.RegistryInfo createInfoForContextRegistry(HolderLookup.RegistryLookup lookup) { return new RegistryOps.RegistryInfo(lookup, lookup, lookup.registryLifecycle()); } private static ReportedException logErrors(Map, Exception> loadingErrors) { RegistryDataLoader.printFullDetailsToLog(loadingErrors); return RegistryDataLoader.createReportWithBriefInfo(loadingErrors); } private static void printFullDetailsToLog(Map, Exception> loadingErrors) { StringWriter collectedErrors = new StringWriter(); PrintWriter errorPrinter = new PrintWriter(collectedErrors); Map> errorsByRegistry = loadingErrors.entrySet().stream().collect(Collectors.groupingBy(e -> ((ResourceKey)e.getKey()).registry(), Collectors.toMap(e -> ((ResourceKey)e.getKey()).identifier(), Map.Entry::getValue))); errorsByRegistry.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(registryEntry -> { errorPrinter.printf(Locale.ROOT, "> Errors in registry %s:%n", registryEntry.getKey()); ((Map)registryEntry.getValue()).entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(elementError -> { errorPrinter.printf(Locale.ROOT, ">> Errors in element %s:%n", elementError.getKey()); ((Exception)elementError.getValue()).printStackTrace(errorPrinter); }); }); errorPrinter.flush(); LOGGER.error("Registry loading errors:\n{}", (Object)collectedErrors); } private static ReportedException createReportWithBriefInfo(Map, Exception> loadingErrors) { CrashReport report = CrashReport.forThrowable(new IllegalStateException("Failed to load registries due to errors"), "Registry Loading"); CrashReportCategory errors = report.addCategory("Loading info"); errors.setDetail("Errors", () -> { StringBuilder briefDetails = new StringBuilder(); loadingErrors.entrySet().stream().sorted(Map.Entry.comparingByKey(ERROR_KEY_COMPARATOR)).forEach(e -> briefDetails.append("\n\t\t").append(((ResourceKey)e.getKey()).registry()).append("/").append(((ResourceKey)e.getKey()).identifier()).append(": ").append(((Exception)e.getValue()).getMessage())); return briefDetails.toString(); }); return new ReportedException(report); } private static void loadElementFromResource(WritableRegistry output, Decoder elementDecoder, RegistryOps ops, ResourceKey elementKey, Resource thunk, RegistrationInfo registrationInfo) throws IOException { try (BufferedReader reader = thunk.openAsReader();){ JsonElement json = StrictJsonParser.parse(reader); DataResult parseResult = elementDecoder.parse(ops, (Object)json); Object parsedElement = parseResult.getOrThrow(); output.register(elementKey, parsedElement, registrationInfo); } } private static void loadContentsFromManager(ResourceManager resourceManager, RegistryOps.RegistryInfoLookup lookup, WritableRegistry registry, Decoder elementDecoder, Map, Exception> loadingErrors) { FileToIdConverter lister = FileToIdConverter.registry(registry.key()); RegistryOps ops = RegistryOps.create(JsonOps.INSTANCE, lookup); for (Map.Entry resourceEntry : lister.listMatchingResources(resourceManager).entrySet()) { Identifier resourceId = resourceEntry.getKey(); ResourceKey elementKey = ResourceKey.create(registry.key(), lister.fileToId(resourceId)); Resource thunk = resourceEntry.getValue(); RegistrationInfo registrationInfo = REGISTRATION_INFO_CACHE.apply(thunk.knownPackInfo()); try { RegistryDataLoader.loadElementFromResource(registry, elementDecoder, ops, elementKey, thunk, registrationInfo); } catch (Exception e) { loadingErrors.put(elementKey, new IllegalStateException(String.format(Locale.ROOT, "Failed to parse %s from pack %s", resourceId, thunk.sourcePackId()), e)); } } TagLoader.loadTagsForRegistry(resourceManager, registry); } private static void loadContentsFromNetwork(Map>, NetworkedRegistryData> entries, ResourceProvider knownDataSource, RegistryOps.RegistryInfoLookup lookup, WritableRegistry registry, Decoder elementDecoder, Map, Exception> loadingErrors) { NetworkedRegistryData registryEntries = entries.get(registry.key()); if (registryEntries == null) { return; } RegistryOps nbtOps = RegistryOps.create(NbtOps.INSTANCE, lookup); RegistryOps jsonOps = RegistryOps.create(JsonOps.INSTANCE, lookup); FileToIdConverter knownDataPathConverter = FileToIdConverter.registry(registry.key()); for (RegistrySynchronization.PackedRegistryEntry entry : registryEntries.elements) { ResourceKey elementKey = ResourceKey.create(registry.key(), entry.id()); Optional data = entry.data(); if (data.isPresent()) { try { DataResult parseResult = elementDecoder.parse(nbtOps, (Object)data.get()); Object parsedElement = parseResult.getOrThrow(); registry.register(elementKey, parsedElement, NETWORK_REGISTRATION_INFO); } catch (Exception e) { loadingErrors.put(elementKey, new IllegalStateException(String.format(Locale.ROOT, "Failed to parse value %s from server", data.get()), e)); } continue; } Identifier knownDataPath = knownDataPathConverter.idToFile(entry.id()); try { Resource thunk = knownDataSource.getResourceOrThrow(knownDataPath); RegistryDataLoader.loadElementFromResource(registry, elementDecoder, jsonOps, elementKey, thunk, NETWORK_REGISTRATION_INFO); } catch (Exception e) { loadingErrors.put(elementKey, new IllegalStateException("Failed to parse local data", e)); } } TagLoader.loadTagsFromNetwork(registryEntries.tags, registry); } @FunctionalInterface private static interface LoadingFunction { public void apply(Loader var1, RegistryOps.RegistryInfoLookup var2); } public record NetworkedRegistryData(List elements, TagNetworkSerialization.NetworkPayload tags) { } private record Loader(RegistryData data, WritableRegistry registry, Map, Exception> loadingErrors) { public void loadFromResources(ResourceManager resourceManager, RegistryOps.RegistryInfoLookup context) { RegistryDataLoader.loadContentsFromManager(resourceManager, context, this.registry, this.data.elementCodec, this.loadingErrors); } public void loadFromNetwork(Map>, NetworkedRegistryData> entries, ResourceProvider knownDataSource, RegistryOps.RegistryInfoLookup context) { RegistryDataLoader.loadContentsFromNetwork(entries, knownDataSource, context, this.registry, this.data.elementCodec, this.loadingErrors); } } public record RegistryData(ResourceKey> key, Codec elementCodec, boolean requiredNonEmpty) { private RegistryData(ResourceKey> key, Codec elementCodec) { this(key, elementCodec, false); } private Loader create(Lifecycle lifecycle, Map, Exception> loadingErrors) { MappedRegistry result = new MappedRegistry(this.key, lifecycle); return new Loader(this, result, loadingErrors); } public void runWithArguments(BiConsumer>, Codec> output) { output.accept(this.key, this.elementCodec); } } }