package net.minecraft.client.multiplayer; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.function.BiConsumer; import java.util.stream.Collectors; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.CrashReportDetail; import net.minecraft.ReportedException; import net.minecraft.core.HolderLookup; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistrySynchronization; import net.minecraft.resources.RegistryDataLoader; import net.minecraft.resources.ResourceKey; import net.minecraft.server.packs.resources.ResourceProvider; import net.minecraft.tags.TagLoader; import net.minecraft.tags.TagNetworkSerialization; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class RegistryDataCollector { @Nullable private RegistryDataCollector.ContentsCollector contentsCollector; @Nullable private RegistryDataCollector.TagCollector tagCollector; public void appendContents(ResourceKey> registryKey, List registryEntries) { if (this.contentsCollector == null) { this.contentsCollector = new RegistryDataCollector.ContentsCollector(); } this.contentsCollector.append(registryKey, registryEntries); } public void appendTags(Map>, TagNetworkSerialization.NetworkPayload> tags) { if (this.tagCollector == null) { this.tagCollector = new RegistryDataCollector.TagCollector(); } tags.forEach(this.tagCollector::append); } private static Registry.PendingTags resolveRegistryTags( RegistryAccess.Frozen registryAccess, ResourceKey> registryKey, TagNetworkSerialization.NetworkPayload payload ) { Registry registry = registryAccess.lookupOrThrow(registryKey); return registry.prepareTagReload(payload.resolve(registry)); } private RegistryAccess loadNewElementsAndTags( ResourceProvider resourceProvider, RegistryDataCollector.ContentsCollector contentCollector, boolean isMemoryConnection ) { LayeredRegistryAccess layeredRegistryAccess = ClientRegistryLayer.createRegistryAccess(); RegistryAccess.Frozen frozen = layeredRegistryAccess.getAccessForLoading(ClientRegistryLayer.REMOTE); Map>, RegistryDataLoader.NetworkedRegistryData> map = new HashMap(); contentCollector.elements .forEach((resourceKey, listx) -> map.put(resourceKey, new RegistryDataLoader.NetworkedRegistryData(listx, TagNetworkSerialization.NetworkPayload.EMPTY))); List> list = new ArrayList(); if (this.tagCollector != null) { this.tagCollector.forEach((resourceKey, networkPayload) -> { if (!networkPayload.isEmpty()) { if (RegistrySynchronization.isNetworkable(resourceKey)) { map.compute(resourceKey, (resourceKeyx, networkedRegistryData) -> { List listxx = networkedRegistryData != null ? networkedRegistryData.elements() : List.of(); return new RegistryDataLoader.NetworkedRegistryData(listxx, networkPayload); }); } else if (!isMemoryConnection) { list.add(resolveRegistryTags(frozen, resourceKey, networkPayload)); } } }); } List> list2 = TagLoader.buildUpdatedLookups(frozen, list); RegistryAccess.Frozen frozen2; try { frozen2 = RegistryDataLoader.load(map, resourceProvider, list2, RegistryDataLoader.SYNCHRONIZED_REGISTRIES).freeze(); } catch (Exception var13) { CrashReport crashReport = CrashReport.forThrowable(var13, "Network Registry Load"); addCrashDetails(crashReport, map, list); throw new ReportedException(crashReport); } RegistryAccess registryAccess = layeredRegistryAccess.replaceFrom(ClientRegistryLayer.REMOTE, frozen2).compositeAccess(); list.forEach(Registry.PendingTags::apply); return registryAccess; } private static void addCrashDetails( CrashReport crashReport, Map>, RegistryDataLoader.NetworkedRegistryData> dynamicRegistries, List> staticRegistries ) { CrashReportCategory crashReportCategory = crashReport.addCategory("Received Elements and Tags"); crashReportCategory.setDetail( "Dynamic Registries", (CrashReportDetail)(() -> (String)dynamicRegistries.entrySet() .stream() .sorted(Comparator.comparing(entry -> ((ResourceKey)entry.getKey()).location())) .map( entry -> String.format( Locale.ROOT, "\n\t\t%s: elements=%d tags=%d", ((ResourceKey)entry.getKey()).location(), ((RegistryDataLoader.NetworkedRegistryData)entry.getValue()).elements().size(), ((RegistryDataLoader.NetworkedRegistryData)entry.getValue()).tags().size() ) ) .collect(Collectors.joining())) ); crashReportCategory.setDetail( "Static Registries", (CrashReportDetail)(() -> (String)staticRegistries.stream() .sorted(Comparator.comparing(pendingTags -> pendingTags.key().location())) .map(pendingTags -> String.format(Locale.ROOT, "\n\t\t%s: tags=%d", pendingTags.key().location(), pendingTags.size())) .collect(Collectors.joining())) ); } private void loadOnlyTags(RegistryDataCollector.TagCollector tagCollector, RegistryAccess.Frozen registryAccess, boolean isMemoryConnection) { tagCollector.forEach((resourceKey, networkPayload) -> { if (isMemoryConnection || RegistrySynchronization.isNetworkable(resourceKey)) { resolveRegistryTags(registryAccess, resourceKey, networkPayload).apply(); } }); } public RegistryAccess.Frozen collectGameRegistries(ResourceProvider resourceProvider, RegistryAccess.Frozen registryAccess, boolean isMemoryConnection) { RegistryAccess registryAccess2; if (this.contentsCollector != null) { registryAccess2 = this.loadNewElementsAndTags(resourceProvider, this.contentsCollector, isMemoryConnection); } else { if (this.tagCollector != null) { this.loadOnlyTags(this.tagCollector, registryAccess, !isMemoryConnection); } registryAccess2 = registryAccess; } return registryAccess2.freeze(); } @Environment(EnvType.CLIENT) static class ContentsCollector { final Map>, List> elements = new HashMap(); public void append(ResourceKey> registryKey, List entries) { ((List)this.elements.computeIfAbsent(registryKey, resourceKey -> new ArrayList())).addAll(entries); } } @Environment(EnvType.CLIENT) static class TagCollector { private final Map>, TagNetworkSerialization.NetworkPayload> tags = new HashMap(); public void append(ResourceKey> registryKey, TagNetworkSerialization.NetworkPayload payload) { this.tags.put(registryKey, payload); } public void forEach(BiConsumer>, ? super TagNetworkSerialization.NetworkPayload> action) { this.tags.forEach(action); } } }