Search in sources :

Example 1 with REGISTRIES

use of net.minecraftforge.registries.ForgeRegistry.REGISTRIES in project MinecraftForge by MinecraftForge.

the class GameData method injectSnapshot.

@SuppressWarnings({ "unchecked", "rawtypes" })
public static Multimap<ResourceLocation, ResourceLocation> injectSnapshot(Map<ResourceLocation, ForgeRegistry.Snapshot> snapshot, boolean injectFrozenData, boolean isLocalWorld) {
    LOGGER.info(REGISTRIES, "Injecting existing registry data into this {} instance", EffectiveSide.get());
    RegistryManager.ACTIVE.registries.forEach((name, reg) -> reg.validateContent(name));
    RegistryManager.ACTIVE.registries.forEach((name, reg) -> reg.dump(name));
    RegistryManager.ACTIVE.registries.forEach((name, reg) -> reg.resetDelegates());
    // Update legacy names
    snapshot = snapshot.entrySet().stream().sorted(// FIXME Registries need dependency ordering, this makes sure blocks are done before items (for ItemCallbacks) but it's lazy as hell
    Map.Entry.comparingByKey()).collect(Collectors.toMap(e -> RegistryManager.ACTIVE.updateLegacyName(e.getKey()), Map.Entry::getValue, (k1, k2) -> k1, LinkedHashMap::new));
    if (isLocalWorld) {
        List<ResourceLocation> missingRegs = snapshot.keySet().stream().filter(name -> !RegistryManager.ACTIVE.registries.containsKey(name)).collect(Collectors.toList());
        if (missingRegs.size() > 0) {
            String header = "Forge Mod Loader detected missing/unknown registrie(s).\n\n" + "There are " + missingRegs.size() + " missing registries in this save.\n" + "If you continue the missing registries will get removed.\n" + "This may cause issues, it is advised that you create a world backup before continuing.\n\n";
            StringBuilder text = new StringBuilder("Missing Registries:\n");
            for (ResourceLocation s : missingRegs) text.append(s).append("\n");
            LOGGER.warn(REGISTRIES, header);
            LOGGER.warn(REGISTRIES, text.toString());
        }
    }
    RegistryManager STAGING = new RegistryManager("STAGING");
    final Map<ResourceLocation, Map<ResourceLocation, Integer[]>> remaps = Maps.newHashMap();
    final LinkedHashMap<ResourceLocation, Map<ResourceLocation, Integer>> missing = Maps.newLinkedHashMap();
    // Load the snapshot into the "STAGING" registry
    snapshot.forEach((key, value) -> {
        final Class<? extends IForgeRegistryEntry> clazz = RegistryManager.ACTIVE.getSuperType(key);
        remaps.put(key, Maps.newLinkedHashMap());
        missing.put(key, Maps.newLinkedHashMap());
        loadPersistentDataToStagingRegistry(RegistryManager.ACTIVE, STAGING, remaps.get(key), missing.get(key), key, value, clazz);
    });
    snapshot.forEach((key, value) -> {
        value.dummied.forEach(dummy -> {
            Map<ResourceLocation, Integer> m = missing.get(key);
            ForgeRegistry<?> reg = STAGING.getRegistry(key);
            // Currently missing locally, we just inject and carry on
            if (m.containsKey(dummy)) {
                if (reg.markDummy(dummy, m.get(dummy)))
                    m.remove(dummy);
            } else if (isLocalWorld) {
                LOGGER.debug(REGISTRIES, "Registry {}: Resuscitating dummy entry {}", key, dummy);
            } else {
                // The server believes this is a dummy block identity, but we seem to have one locally. This is likely a conflict
                // in mod setup - Mark this entry as a dummy
                int id = reg.getID(dummy);
                LOGGER.warn(REGISTRIES, "Registry {}: The ID {} @ {} is currently locally mapped - it will be replaced with a dummy for this session", dummy, key, id);
                reg.markDummy(dummy, id);
            }
        });
    });
    int count = missing.values().stream().mapToInt(Map::size).sum();
    if (count > 0) {
        LOGGER.debug(REGISTRIES, "There are {} mappings missing - attempting a mod remap", count);
        Multimap<ResourceLocation, ResourceLocation> defaulted = ArrayListMultimap.create();
        Multimap<ResourceLocation, ResourceLocation> failed = ArrayListMultimap.create();
        missing.entrySet().stream().filter(e -> e.getValue().size() > 0).forEach(m -> {
            ResourceLocation name = m.getKey();
            ForgeRegistry<?> reg = STAGING.getRegistry(name);
            RegistryEvent.MissingMappings<?> event = reg.getMissingEvent(name, m.getValue());
            MinecraftForge.EVENT_BUS.post(event);
            List<MissingMappings.Mapping<?>> lst = event.getAllMappings().stream().filter(e -> e.getAction() == MissingMappings.Action.DEFAULT).sorted((a, b) -> a.toString().compareTo(b.toString())).collect(Collectors.toList());
            if (!lst.isEmpty()) {
                LOGGER.error(REGISTRIES, () -> LogMessageAdapter.adapt(sb -> {
                    sb.append("Unidentified mapping from registry ").append(name).append('\n');
                    lst.stream().sorted().forEach(map -> sb.append('\t').append(map.key).append(": ").append(map.id).append('\n'));
                }));
            }
            event.getAllMappings().stream().filter(e -> e.getAction() == MissingMappings.Action.FAIL).forEach(fail -> failed.put(name, fail.key));
            final Class<? extends IForgeRegistryEntry> clazz = RegistryManager.ACTIVE.getSuperType(name);
            processMissing(clazz, name, STAGING, event, m.getValue(), remaps.get(name), defaulted.get(name), failed.get(name), !isLocalWorld);
        });
        if (!defaulted.isEmpty() && !isLocalWorld)
            return defaulted;
        if (!defaulted.isEmpty()) {
            String header = "Forge Mod Loader detected missing registry entries.\n\n" + "There are " + defaulted.size() + " missing entries in this save.\n" + "If you continue the missing entries will get removed.\n" + "A world backup will be automatically created in your saves directory.\n\n";
            StringBuilder buf = new StringBuilder();
            defaulted.asMap().forEach((name, entries) -> {
                buf.append("Missing ").append(name).append(":\n");
                entries.stream().sorted((o1, o2) -> o1.compareNamespaced(o2)).forEach(rl -> buf.append("    ").append(rl).append("\n"));
                buf.append("\n");
            });
            LOGGER.warn(REGISTRIES, header);
            LOGGER.warn(REGISTRIES, buf.toString());
        }
        if (!defaulted.isEmpty()) {
            if (isLocalWorld)
                LOGGER.error(REGISTRIES, "There are unidentified mappings in this world - we are going to attempt to process anyway");
        }
    }
    if (injectFrozenData) {
        // If we're loading from disk, we can actually substitute air in the block map for anything that is otherwise "missing". This keeps the reference in the map, in case
        // the block comes back later
        missing.forEach((name, m) -> {
            if (m.isEmpty())
                return;
            ForgeRegistry<?> reg = STAGING.getRegistry(name);
            m.forEach((rl, id) -> reg.markDummy(rl, id));
        });
        // If we're loading up the world from disk, we want to add in the new data that might have been provisioned by mods
        // So we load it from the frozen persistent registry
        RegistryManager.ACTIVE.registries.forEach((name, reg) -> {
            final Class<? extends IForgeRegistryEntry> clazz = RegistryManager.ACTIVE.getSuperType(name);
            loadFrozenDataToStagingRegistry(STAGING, name, remaps.get(name), clazz);
        });
    }
    // Validate that all the STAGING data is good
    STAGING.registries.forEach((name, reg) -> reg.validateContent(name));
    // Load the STAGING registry into the ACTIVE registry
    // for (Map.Entry<ResourceLocation, IForgeRegistry<? extends IForgeRegistryEntry<?>>> r : RegistryManager.ACTIVE.registries.entrySet())
    RegistryManager.ACTIVE.registries.forEach((key, value) -> {
        final Class<? extends IForgeRegistryEntry> registrySuperType = RegistryManager.ACTIVE.getSuperType(key);
        loadRegistry(key, STAGING, RegistryManager.ACTIVE, registrySuperType, true);
    });
    RegistryManager.ACTIVE.registries.forEach((name, reg) -> {
        reg.bake();
        // Dump the active registry
        reg.dump(name);
    });
    // Tell mods that the ids have changed
    fireRemapEvent(remaps, false);
    // The id map changed, ensure we apply object holders
    ObjectHolderRegistry.applyObjectHolders();
    // Return an empty list, because we're good
    return ArrayListMultimap.create();
}
Also used : ResourceLocation(net.minecraft.resources.ResourceLocation) SensorType(net.minecraft.world.entity.ai.sensing.SensorType) EffectiveSide(net.minecraftforge.fml.util.thread.EffectiveSide) TreeDecoratorType(net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType) Item(net.minecraft.world.item.Item) IModStateTransition(net.minecraftforge.fml.IModStateTransition) MenuType(net.minecraft.world.inventory.MenuType) FoliagePlacerType(net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType) Activity(net.minecraft.world.entity.schedule.Activity) Registry(net.minecraft.core.Registry) RegistryEvent(net.minecraftforge.event.RegistryEvent) StatType(net.minecraft.stats.StatType) ModLoadingContext(net.minecraftforge.fml.ModLoadingContext) com.google.common.collect(com.google.common.collect) StateDefinition(net.minecraft.world.level.block.state.StateDefinition) DefaultedRegistry(net.minecraft.core.DefaultedRegistry) MemoryModuleType(net.minecraft.world.entity.ai.memory.MemoryModuleType) StaticTags(net.minecraft.tags.StaticTags) PoiType(net.minecraft.world.entity.ai.village.poi.PoiType) DefaultAttributes(net.minecraft.world.entity.ai.attributes.DefaultAttributes) LogMessageAdapter(net.minecraftforge.common.util.LogMessageAdapter) Collectors(java.util.stream.Collectors) Potion(net.minecraft.world.item.alchemy.Potion) Schedule(net.minecraft.world.entity.schedule.Schedule) IdMapper(net.minecraft.core.IdMapper) DebugLevelSource(net.minecraft.world.level.levelgen.DebugLevelSource) Logger(org.apache.logging.log4j.Logger) Stream(java.util.stream.Stream) BlockEntityType(net.minecraft.world.level.block.entity.BlockEntityType) MappedRegistry(net.minecraft.core.MappedRegistry) SoundEvent(net.minecraft.sounds.SoundEvent) AirBlock(net.minecraft.world.level.block.AirBlock) Motive(net.minecraft.world.entity.decoration.Motive) Enchantment(net.minecraft.world.item.enchantment.Enchantment) java.util(java.util) ForgeWorldPreset(net.minecraftforge.common.world.ForgeWorldPreset) EntityType(net.minecraft.world.entity.EntityType) BlockState(net.minecraft.world.level.block.state.BlockState) CompletableFuture(java.util.concurrent.CompletableFuture) Biome(net.minecraft.world.level.biome.Biome) Function(java.util.function.Function) GlobalLootModifierSerializer(net.minecraftforge.common.loot.GlobalLootModifierSerializer) BlockStateProviderType(net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProviderType) StructureFeature(net.minecraft.world.level.levelgen.feature.StructureFeature) VillagerProfession(net.minecraft.world.entity.npc.VillagerProfession) BiConsumer(java.util.function.BiConsumer) Fluid(net.minecraft.world.level.material.Fluid) EntityDataSerializer(net.minecraft.network.syncher.EntityDataSerializer) EnhancedRuntimeException(net.minecraftforge.fml.util.EnhancedRuntimeException) Nullable(javax.annotation.Nullable) Keys(net.minecraftforge.registries.ForgeRegistries.Keys) BlockItem(net.minecraft.world.item.BlockItem) Executor(java.util.concurrent.Executor) RecipeSerializer(net.minecraft.world.item.crafting.RecipeSerializer) ParticleType(net.minecraft.core.particles.ParticleType) WorldCarver(net.minecraft.world.level.levelgen.carver.WorldCarver) Lifecycle(com.mojang.serialization.Lifecycle) MissingMappings(net.minecraftforge.event.RegistryEvent.MissingMappings) Field(java.lang.reflect.Field) REGISTRIES(net.minecraftforge.registries.ForgeRegistry.REGISTRIES) ResourceKey(net.minecraft.resources.ResourceKey) Material(net.minecraft.world.level.material.Material) Attribute(net.minecraft.world.entity.ai.attributes.Attribute) Feature(net.minecraft.world.level.levelgen.feature.Feature) MinecraftForge(net.minecraftforge.common.MinecraftForge) Validate(org.apache.commons.lang3.Validate) StartupMessageManager(net.minecraftforge.fml.StartupMessageManager) ForgeTagHandler(net.minecraftforge.common.ForgeTagHandler) Block(net.minecraft.world.level.block.Block) ChunkStatus(net.minecraft.world.level.chunk.ChunkStatus) LogManager(org.apache.logging.log4j.LogManager) MobEffect(net.minecraft.world.effect.MobEffect) RegistryEvent(net.minecraftforge.event.RegistryEvent) ResourceLocation(net.minecraft.resources.ResourceLocation)

Example 2 with REGISTRIES

use of net.minecraftforge.registries.ForgeRegistry.REGISTRIES in project MinecraftForge by MinecraftForge.

the class HandshakeHandler method handleRegistryLoading.

private boolean handleRegistryLoading(final Supplier<NetworkEvent.Context> contextSupplier) {
    // We use a countdown latch to suspend the impl thread pending the client thread processing the registry data
    AtomicBoolean successfulConnection = new AtomicBoolean(false);
    CountDownLatch block = new CountDownLatch(1);
    contextSupplier.get().enqueueWork(() -> {
        LOGGER.debug(FMLHSMARKER, "Injecting registry snapshot from server.");
        final Multimap<ResourceLocation, ResourceLocation> missingData = GameData.injectSnapshot(registrySnapshots, false, false);
        LOGGER.debug(FMLHSMARKER, "Snapshot injected.");
        if (!missingData.isEmpty()) {
            LOGGER.error(FMLHSMARKER, "Missing registry data for impl connection:\n{}", LogMessageAdapter.adapt(sb -> missingData.forEach((reg, entry) -> sb.append("\t").append(reg).append(": ").append(entry).append('\n'))));
        }
        successfulConnection.set(missingData.isEmpty());
        block.countDown();
    });
    LOGGER.debug(FMLHSMARKER, "Waiting for registries to load.");
    try {
        block.await();
    } catch (InterruptedException e) {
        Thread.interrupted();
    }
    if (successfulConnection.get()) {
        LOGGER.debug(FMLHSMARKER, "Registry load complete, continuing handshake.");
    } else {
        LOGGER.error(FMLHSMARKER, "Failed to load registry, closing connection.");
        this.manager.disconnect(new TextComponent("Failed to synchronize registry data from server, closing connection"));
    }
    return successfulConnection.get();
}
Also used : ResourceLocation(net.minecraft.resources.ResourceLocation) java.util(java.util) ForgeRegistry(net.minecraftforge.registries.ForgeRegistry) ServerLoginPacketListenerImpl(net.minecraft.server.network.ServerLoginPacketListenerImpl) ServerboundCustomQueryPacket(net.minecraft.network.protocol.login.ServerboundCustomQueryPacket) Connection(net.minecraft.network.Connection) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Multimap(com.google.common.collect.Multimap) LogMessageAdapter(net.minecraftforge.common.util.LogMessageAdapter) REGISTRIES(net.minecraftforge.registries.ForgeRegistry.REGISTRIES) Maps(com.google.common.collect.Maps) Supplier(java.util.function.Supplier) CountDownLatch(java.util.concurrent.CountDownLatch) TextComponent(net.minecraft.network.chat.TextComponent) MarkerManager(org.apache.logging.log4j.MarkerManager) Logger(org.apache.logging.log4j.Logger) GameData(net.minecraftforge.registries.GameData) SimpleChannel(net.minecraftforge.network.simple.SimpleChannel) BiConsumer(java.util.function.BiConsumer) ClientIntentionPacket(net.minecraft.network.protocol.handshake.ClientIntentionPacket) LogManager(org.apache.logging.log4j.LogManager) Marker(org.apache.logging.log4j.Marker) IntSupplier(java.util.function.IntSupplier) ClientboundCustomQueryPacket(net.minecraft.network.protocol.login.ClientboundCustomQueryPacket) TextComponent(net.minecraft.network.chat.TextComponent) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ResourceLocation(net.minecraft.resources.ResourceLocation) CountDownLatch(java.util.concurrent.CountDownLatch)

Aggregations

java.util (java.util)2 BiConsumer (java.util.function.BiConsumer)2 ResourceLocation (net.minecraft.resources.ResourceLocation)2 com.google.common.collect (com.google.common.collect)1 Maps (com.google.common.collect.Maps)1 Multimap (com.google.common.collect.Multimap)1 Lifecycle (com.mojang.serialization.Lifecycle)1 Field (java.lang.reflect.Field)1 CompletableFuture (java.util.concurrent.CompletableFuture)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 Executor (java.util.concurrent.Executor)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 Function (java.util.function.Function)1 IntSupplier (java.util.function.IntSupplier)1 Supplier (java.util.function.Supplier)1 Collectors (java.util.stream.Collectors)1 Stream (java.util.stream.Stream)1 Nullable (javax.annotation.Nullable)1 DefaultedRegistry (net.minecraft.core.DefaultedRegistry)1 IdMapper (net.minecraft.core.IdMapper)1