Exemple #1
0
 @Override
 public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
   if (evt instanceof ConnectionType && side == Side.SERVER) {
     FMLLog.info("Timeout occurred, assuming a vanilla client");
     kickVanilla();
   }
 }
Exemple #2
0
 private boolean handleVanilla(Packet msg) {
   if (state == ConnectionState.AWAITING_HANDSHAKE && msg instanceof S01PacketJoinGame) {
     handshakeChannel.pipeline().fireUserEventTriggered(msg);
   } else {
     FMLLog.info(
         "Unexpected packet during modded negotiation - assuming vanilla or keepalives : %s",
         msg.getClass().getName());
   }
   return false;
 }
Exemple #3
0
 private void completeClientSideConnection(ConnectionType type) {
   this.connectionType = type;
   FMLLog.info(
       "[%s] Client side %s connection established",
       Thread.currentThread().getName(), this.connectionType.name().toLowerCase(Locale.ENGLISH));
   this.state = ConnectionState.CONNECTED;
   FMLCommonHandler.instance()
       .bus()
       .post(
           new FMLNetworkEvent.ClientConnectedToServerEvent(manager, this.connectionType.name()));
 }
  private List<String> loadGenericRegistries(GameDataSnapshot snapshot, GameData existing) {
    List<String> result = Lists.newArrayList();
    for (Map.Entry<String, FMLControlledNamespacedRegistry<?>> e :
        existing.genericRegistries.entrySet()) {
      String regName = e.getKey();
      FMLControlledNamespacedRegistry<?> registry = e.getValue();
      FMLControlledNamespacedRegistry<?> newRegistry = genericRegistries.get(regName);
      if (newRegistry == null) {
        newRegistry = registry.makeShallowCopy();
        genericRegistries.put(regName, newRegistry);
      }

      GameDataSnapshot.Entry regSnap = snapshot.entries.get("fmlgr:" + regName);
      if (regSnap == null) {
        FMLLog.info(
            "Weird, there was no registry data for registry %s found in the snapshot", regName);
        continue;
      }

      for (Entry<String, Integer> entry : regSnap.ids.entrySet()) {
        String entryName = entry.getKey();
        int entryId = entry.getValue();
        int currId = registry.getId(entryName);

        if (currId == -1) {
          FMLLog.info("Found a missing id in registry %s from the world %s", regName, entryName);
          result.add(regName + "{" + entryName + "}=" + entryId);
          continue; // no block/item -> nothing to add
        } else if (currId != entryId) {
          FMLLog.fine(
              "Fixed registry %s id mismatch %s: %d (init) -> %d (map).",
              regName, entryName, currId, entryId);
        }

        newRegistry.add(entryId, entryName, registry.getRaw(entryName));
      }
    }
    return result;
  }
Exemple #5
0
 public void serverToClientHandshake(EntityPlayerMP player) {
   this.player = player;
   insertIntoChannel();
   Boolean fml = this.manager.channel().attr(NetworkRegistry.FML_MARKER).get();
   if (fml != null && fml.booleanValue()) {
     // FML on client, send server hello
     // TODO: Make this cleaner as it uses netty magic 0.o
   } else {
     serverInitiateHandshake();
     FMLLog.info("Connection received without FML marker, assuming vanilla.");
     this.completeServerSideConnection(ConnectionType.VANILLA);
   }
 }
Exemple #6
0
 private synchronized void completeServerSideConnection(ConnectionType type) {
   this.connectionType = type;
   FMLLog.info(
       "[%s] Server side %s connection established",
       Thread.currentThread().getName(), this.connectionType.name().toLowerCase(Locale.ENGLISH));
   this.state = ConnectionState.CONNECTED;
   FMLCommonHandler.instance()
       .bus()
       .post(new FMLNetworkEvent.ServerConnectionFromClientEvent(manager));
   if (DEBUG_HANDSHAKE)
     manager.closeChannel(
         new ChatComponentText("Handshake Complete review log file for details."));
   scm.initializeConnectionToPlayer(manager, player, serverHandler);
 }
  public static List<String> processIdRematches(
      Iterable<MissingMapping> missedMappings,
      boolean isLocalWorld,
      GameData gameData,
      Map<String, Integer[]> remapBlocks,
      Map<String, Integer[]> remapItems) {
    List<String> failed = Lists.newArrayList();
    List<String> ignored = Lists.newArrayList();
    List<String> warned = Lists.newArrayList();
    List<String> defaulted = Lists.newArrayList();

    for (MissingMapping remap : missedMappings) {
      FMLMissingMappingsEvent.Action action = remap.getAction();

      if (action == FMLMissingMappingsEvent.Action.REMAP) {
        // block/item re-mapped, finish the registration with the new name/object, but the old id
        int currId, newId;
        String newName;

        if (remap.type == Type.BLOCK) {
          currId = getMain().iBlockRegistry.getId((Block) remap.getTarget());
          newName = getMain().iBlockRegistry.getNameForObject(remap.getTarget()).toString();
          FMLLog.fine("The Block %s is being remapped to %s.", remap.name, newName);

          newId = gameData.registerBlock((Block) remap.getTarget(), newName, remap.id);
          gameData.iBlockRegistry.addAlias(remap.name, newName);
        } else {
          currId = getMain().iItemRegistry.getId((Item) remap.getTarget());
          newName = getMain().iItemRegistry.getNameForObject(remap.getTarget()).toString();
          FMLLog.fine("The Item %s is being remapped to %s.", remap.name, newName);

          newId = gameData.registerItem((Item) remap.getTarget(), newName, remap.id);
          gameData.iItemRegistry.addAlias(remap.name, newName);
        }

        if (newId != remap.id) throw new IllegalStateException();

        if (currId != newId) {
          FMLLog.info(
              "Fixed %s id mismatch %s: %d (init) -> %d (map).",
              remap.type == Type.BLOCK ? "block" : "item", newName, currId, newId);
          (remap.type == Type.BLOCK ? remapBlocks : remapItems)
              .put(newName, new Integer[] {currId, newId});
        }
      } else if (action == FMLMissingMappingsEvent.Action.BLOCKONLY) {
        // Pulled out specifically so the block doesn't get reassigned a new ID just because it's
        // Item block has gone away
        FMLLog.fine(
            "The ItemBlock %s is no longer present in the game. The residual block will remain",
            remap.name);
      } else {
        // block item missing, warn as requested and block the id
        if (action == FMLMissingMappingsEvent.Action.DEFAULT) {
          defaulted.add(remap.name);
        } else if (action == FMLMissingMappingsEvent.Action.IGNORE) {
          ignored.add(remap.name);
        } else if (action == FMLMissingMappingsEvent.Action.FAIL) {
          failed.add(remap.name);
        } else if (action == FMLMissingMappingsEvent.Action.WARN) {
          warned.add(remap.name);
        }

        gameData.block(remap.id); // prevent the id from being reused later
      }
    }

    if (!defaulted.isEmpty()) {
      String text =
          "Forge Mod Loader detected missing blocks/items.\n\n"
              + "There are "
              + defaulted.size()
              + " missing blocks and items in this save.\n"
              + "If you continue the missing blocks/items will get removed.\n"
              + "A world backup will be automatically created in your saves directory.\n\n"
              + "Missing Blocks/Items:\n";

      for (String s : defaulted) text += s + "\n";

      boolean confirmed = StartupQuery.confirm(text);
      if (!confirmed) StartupQuery.abort();

      try {
        String skip = System.getProperty("fml.doNotBackup");
        if (skip == null || !"true".equals(skip)) {
          ZipperUtil.backupWorld();
        } else {
          for (int x = 0; x < 10; x++)
            FMLLog.severe("!!!!!!!!!! UPDATING WORLD WITHOUT DOING BACKUP !!!!!!!!!!!!!!!!");
        }
      } catch (IOException e) {
        StartupQuery.notify("The world backup couldn't be created.\n\n" + e);
        StartupQuery.abort();
      }

      warned.addAll(defaulted);
    }
    if (!failed.isEmpty()) {
      FMLLog.severe(
          "This world contains blocks and items that refuse to be remapped. The world will not be loaded");
      return failed;
    }
    if (!warned.isEmpty()) {
      FMLLog.severe("This world contains block and item mappings that may cause world breakage");
      return failed;
    } else if (!ignored.isEmpty()) {
      FMLLog.fine("There were %d missing mappings that have been ignored", ignored.size());
    }
    return failed;
  }
  public static List<String> injectSnapshot(
      GameDataSnapshot snapshot, boolean injectFrozenData, boolean isLocalWorld) {
    FMLLog.info(
        "Injecting existing block and item data into this %s instance",
        FMLCommonHandler.instance().getEffectiveSide().isServer() ? "server" : "client");
    Map<String, Integer[]> remapBlocks = Maps.newHashMap();
    Map<String, Integer[]> remapItems = Maps.newHashMap();
    LinkedHashMap<String, Integer> missingBlocks = new LinkedHashMap<String, Integer>();
    LinkedHashMap<String, Integer> missingItems = new LinkedHashMap<String, Integer>();
    getMain().testConsistency();
    getMain().iBlockRegistry.dump();
    getMain().iItemRegistry.dump();

    getMain().iItemRegistry.resetSubstitutionDelegates();

    GameDataSnapshot.Entry blocks = snapshot.entries.get("fml:blocks");
    GameDataSnapshot.Entry items = snapshot.entries.get("fml:items");

    GameData newData = new GameData();

    for (int id : blocks.blocked) {
      newData.block(id);
    }

    for (Map.Entry<String, String> entry : blocks.aliases.entrySet()) {
      newData.iBlockRegistry.addAlias(entry.getKey(), entry.getValue());
    }

    for (Map.Entry<String, String> entry : items.aliases.entrySet()) {
      newData.iItemRegistry.addAlias(entry.getKey(), entry.getValue());
    }

    for (String entry : blocks.substitutions) {
      newData.iBlockRegistry.activateSubstitution(entry);
    }
    for (String entry : items.substitutions) {
      newData.iItemRegistry.activateSubstitution(entry);
    }
    if (injectFrozenData) {
      for (String newBlockSubstitution : getMain().blockSubstitutions.keySet()) {
        if (!blocks.substitutions.contains(newBlockSubstitution)) {
          newData.iBlockRegistry.activateSubstitution(newBlockSubstitution);
        }
      }
      for (String newItemSubstitution : getMain().itemSubstitutions.keySet()) {
        if (!items.substitutions.contains(newItemSubstitution)) {
          newData.iItemRegistry.activateSubstitution(newItemSubstitution);
        }
      }
    }

    // Clear State map for it's ready for us to register below.
    GameData.BLOCKSTATE_TO_ID.clear();

    // process blocks and items in the world, blocks in the first pass, items in the second
    // blocks need to be added first for proper ItemBlock handling
    for (int pass = 0; pass < 2; pass++) {
      boolean isBlock = (pass == 0);
      Map<String, Integer> ids = (isBlock ? blocks.ids : items.ids);

      for (Entry<String, Integer> entry : ids.entrySet()) {
        String itemName = entry.getKey();
        int newId = entry.getValue();
        int currId =
            isBlock
                ? getMain().iBlockRegistry.getId(itemName)
                : getMain().iItemRegistry.getId(itemName);

        if (currId == -1) {
          FMLLog.info("Found a missing id from the world %s", itemName);
          (isBlock ? missingBlocks : missingItems).put(entry.getKey(), newId);
          continue; // no block/item -> nothing to add
        } else if (currId != newId) {
          FMLLog.fine(
              "Fixed %s id mismatch %s: %d (init) -> %d (map).",
              isBlock ? "block" : "item", itemName, currId, newId);
          (isBlock ? remapBlocks : remapItems).put(itemName, new Integer[] {currId, newId});
        }

        // register
        if (isBlock) {
          currId =
              newData.registerBlock(getMain().iBlockRegistry.getRaw(itemName), itemName, newId);
        } else {
          currId = newData.registerItem(getMain().iItemRegistry.getRaw(itemName), itemName, newId);
        }

        if (currId != newId) {
          throw new IllegalStateException(
              String.format(
                  "Can't map %s %s to id %d (seen at: %d), already occupied by %s, blocked %b, ItemBlock %b",
                  isBlock ? "block" : "item",
                  itemName,
                  newId,
                  currId,
                  isBlock
                      ? newData.iBlockRegistry.getRaw(newId)
                      : newData.iItemRegistry.getRaw(newId),
                  newData.blockedIds.contains(newId),
                  isBlock ? false : (getMain().iItemRegistry.getRaw(currId) instanceof ItemBlock)));
        }
      }
    }

    List<String> missedMappings =
        Loader.instance()
            .fireMissingMappingEvent(
                missingBlocks, missingItems, isLocalWorld, newData, remapBlocks, remapItems);
    if (!missedMappings.isEmpty()) return missedMappings;

    // If we got here - the load was accepted. We'll load generic repositories here.
    // Generic registries can fail by returning a missing mapping.
    missedMappings = newData.loadGenericRegistries(snapshot, getMain());
    if (!missedMappings.isEmpty()) return missedMappings;

    if (injectFrozenData) // add blocks + items missing from the map
    {
      Map<String, Integer> newBlocks =
          frozen.iBlockRegistry.getEntriesNotIn(newData.iBlockRegistry);
      Map<String, Integer> newItems = frozen.iItemRegistry.getEntriesNotIn(newData.iItemRegistry);

      if (!newBlocks.isEmpty() || !newItems.isEmpty()) {
        FMLLog.info("Injecting new block and item data into this server instance.");

        for (int pass = 0; pass < 2; pass++) {
          boolean isBlock = pass == 0;
          Map<String, Integer> missing = (pass == 0) ? newBlocks : newItems;
          Map<String, Integer[]> remaps = (isBlock ? remapBlocks : remapItems);

          for (Entry<String, Integer> entry : missing.entrySet()) {
            String itemName = entry.getKey();
            int currId = entry.getValue();
            int newId;

            if (isBlock) {
              newId =
                  newData.registerBlock(frozen.iBlockRegistry.getRaw(itemName), itemName, currId);
            } else {
              newId = newData.registerItem(frozen.iItemRegistry.getRaw(itemName), itemName, currId);
            }

            FMLLog.info(
                "Injected new block/item %s: %d (init) -> %d (map).", itemName, currId, newId);

            if (newId != currId) // a new id was assigned
            {
              remaps.put(itemName, new Integer[] {entry.getValue(), newId});
            }
          }
        }
      }
    }

    newData.testConsistency();
    getMain().set(newData);

    getMain().iBlockRegistry.dump();
    getMain().iItemRegistry.dump();
    Loader.instance().fireRemapEvent(remapBlocks, remapItems);
    // The id map changed, ensure we apply object holders
    ObjectHolderRegistry.INSTANCE.applyObjectHolders();
    return ImmutableList.of();
  }
  @SideOnly(Side.CLIENT)
  @SubscribeEvent(priority = EventPriority.LOWEST)
  public void bakeModels(ModelBakeEvent event) {
    ItemModelMesher itemModelMesher = Minecraft.getMinecraft().getRenderItem().getItemModelMesher();
    for (Object object : jsonDestroyer.objectsToDestroy) {
      if (object instanceof Block && object instanceof ITexturedBlock) {
        ITexturedBlock textureProvdier = (ITexturedBlock) object;
        Block block = (Block) object;
        for (int i = 0; i < textureProvdier.amountOfStates(); i++) {
          HashMap<EnumFacing, TextureAtlasSprite> textureMap =
              new HashMap<EnumFacing, TextureAtlasSprite>();
          for (EnumFacing side : EnumFacing.VALUES) {
            for (BlockIconInfo iconInfo : blockIconInfoList) {
              if (iconInfo.getBlock() == block
                  && iconInfo.getMeta() == i
                  && iconInfo.getSide() == side) {
                if (blockIconList.containsKey(iconInfo))
                  textureMap.put(side, blockIconList.get(iconInfo));
              }
            }
          }
          if (textureMap.isEmpty()) {
            return;
          }

          BlockModel model =
              new BlockModel(
                  textureMap, block.getStateFromMeta(i).getBlock() instanceof IOpaqueBlock);
          ModelResourceLocation modelResourceLocation =
              getModelResourceLocation(block.getStateFromMeta(i));
          //                    if(event.modelManager.getModel(modelResourceLocation) !=
          // event.modelManager.getMissingModel()){
          //                        FMLLog.info("Model found @ " + modelResourceLocation.toString()
          // + ", this means a resource pack is overriding it or a modder is doing something bad.
          // JSON-Destoyer will not attempt to create a model for it.");
          //                        continue;
          //                    }
          event.modelRegistry.putObject(modelResourceLocation, model);
          ModelResourceLocation inventory = getBlockinventoryResourceLocation(block);
          //                    if(event.modelManager.getModel(inventory) !=
          // event.modelManager.getMissingModel()){
          //                        FMLLog.info("Model found @ " + inventory.toString() + ", this
          // means a resource pack is overriding it or a modder is doing something bad.
          // JSON-Destoyer will not attempt to create a model for it.");
          //                        continue;
          //                    }
          event.modelRegistry.putObject(inventory, model);
          itemModelMesher.register(Item.getItemFromBlock(block), i, inventory);
          event.modelRegistry.putObject(modelResourceLocation, model);
          itemModelMesher.register(Item.getItemFromBlock(block), i, modelResourceLocation);
        }
      } else if (object instanceof ITexturedFluid && object instanceof BlockFluidBase) {
        final BlockFluidBase fluid = (BlockFluidBase) object;
        final ModelResourceLocation fluidLocation =
            new ModelResourceLocation(fluid.getFluid().getFlowing(), "fluid");
        //                if(event.modelManager.getModel(fluidLocation) !=
        // event.modelManager.getMissingModel()){
        //                    FMLLog.info("Model found @ " + fluidLocation.toString() + ", this
        // means a resource pack is overriding it or a modder is doing something bad. JSON-Destoyer
        // will not attempt to create a model for it.");
        //                    continue;
        //                }
        Item fluidItem = Item.getItemFromBlock(fluid);
        ModelBakery.addVariantName(fluidItem);
        ModelLoader.setCustomMeshDefinition(
            fluidItem,
            new ItemMeshDefinition() {
              public ModelResourceLocation getModelLocation(ItemStack stack) {
                return fluidLocation;
              }
            });
        ModelLoader.setCustomStateMapper(
            fluid,
            new StateMapperBase() {
              protected ModelResourceLocation getModelResourceLocation(IBlockState state) {
                return fluidLocation;
              }
            });

        for (int i = 0; i < 16; i++) {
          ModelResourceLocation location =
              new ModelResourceLocation(getBlockResourceLocation(fluid), "level=" + i);
          if (event.modelManager.getModel(location) != event.modelManager.getMissingModel()) {
            FMLLog.info(
                "Model found @ "
                    + location.toString()
                    + ", this means a resource pack is overriding it or a modder is doing something bad. JSON-Destoyer will not attempt to create a model for it.");
            continue;
          }
          ModelFluid modelFluid = new ModelFluid(fluid.getFluid());
          Function<ResourceLocation, TextureAtlasSprite> textureGetter =
              new Function<ResourceLocation, TextureAtlasSprite>() {
                public TextureAtlasSprite apply(ResourceLocation location) {
                  return fluidIcons.get(fluid);
                }
              };
          IFlexibleBakedModel bakedModel =
              modelFluid.bake(
                  modelFluid.getDefaultState(), DefaultVertexFormats.BLOCK, textureGetter);

          event.modelRegistry.putObject(location, bakedModel);
        }
        ModelResourceLocation inventoryLocation =
            new ModelResourceLocation(getBlockResourceLocation(fluid), "inventory");
        //                if(event.modelManager.getModel(inventoryLocation) !=
        // event.modelManager.getMissingModel()){
        //                    FMLLog.info("Model found @ " + inventoryLocation.toString() + ", this
        // means a resource pack is overriding it or a modder is doing something bad. JSON-Destoyer
        // will not attempt to create a model for it.");
        //                    continue;
        //                }
        ModelFluid modelFluid = new ModelFluid(fluid.getFluid());
        Function<ResourceLocation, TextureAtlasSprite> textureGetter =
            new Function<ResourceLocation, TextureAtlasSprite>() {
              public TextureAtlasSprite apply(ResourceLocation location) {
                return fluidIcons.get(fluid);
              }
            };
        IFlexibleBakedModel bakedModel =
            modelFluid.bake(modelFluid.getDefaultState(), DefaultVertexFormats.ITEM, textureGetter);

        event.modelRegistry.putObject(inventoryLocation, bakedModel);
      } else if (object instanceof Item && object instanceof ITexturedItem) {
        ITexturedItem iTexturedItem = (ITexturedItem) object;
        Item item = (Item) object;
        for (int i = 0; i < iTexturedItem.getMaxMeta(); i++) {
          TextureAtlasSprite texture = null;
          ItemIconInfo itemIconInfo = null;
          for (ItemIconInfo info : itemIcons) {
            if (info.damage == i && info.getItem() == item && info.isBucket == false) {
              texture = info.getSprite();
              itemIconInfo = info;
              break;
            }
          }
          if (texture == null) {
            break;
          }

          ModelResourceLocation inventory;
          inventory = getItemInventoryResourceLocation(item);

          if (iTexturedItem.getMaxMeta() != 1) {
            if (item.getModel(new ItemStack(item, 1, i), Minecraft.getMinecraft().thePlayer, 0)
                != null) {
              inventory =
                  item.getModel(new ItemStack(item, 1, i), Minecraft.getMinecraft().thePlayer, 0);
            }
          }
          //                    if(event.modelManager.getModel(inventory) !=
          // event.modelManager.getMissingModel()){
          //                        FMLLog.info("Model found @ " + inventory.toString() + ", this
          // means a resource pack is overriding it or a modder is doing something bad.
          // JSON-Destoyer will not attempt to create a model for it.");
          //                        continue;
          //                    }

          final TextureAtlasSprite finalTexture = texture;
          Function<ResourceLocation, TextureAtlasSprite> textureGetter =
              new Function<ResourceLocation, TextureAtlasSprite>() {
                public TextureAtlasSprite apply(ResourceLocation location) {
                  return finalTexture;
                }
              };
          ImmutableList.Builder<ResourceLocation> builder = ImmutableList.builder();
          builder.add(new ResourceLocation(itemIconInfo.textureName));
          CustomModel itemLayerModel = new CustomModel(builder.build());
          IBakedModel model =
              itemLayerModel.bake(
                  ItemLayerModel.instance.getDefaultState(),
                  DefaultVertexFormats.ITEM,
                  textureGetter);
          itemModelMesher.register(item, i, inventory);
          event.modelRegistry.putObject(inventory, model);
        }
      } else if (object instanceof Item && object instanceof ITexturedBucket) {
        ITexturedBucket iTexturedBucket = (ITexturedBucket) object;
        Item item = (Item) object;
        for (int i = 0; i < iTexturedBucket.getMaxMeta(); i++) {
          ModelResourceLocation inventory;
          inventory = getItemInventoryResourceLocation(item);
          if (iTexturedBucket.getMaxMeta() != 1) {
            if (item.getModel(new ItemStack(item, 1, i), Minecraft.getMinecraft().thePlayer, 0)
                != null) {
              inventory =
                  item.getModel(new ItemStack(item, 1, i), Minecraft.getMinecraft().thePlayer, 0);
            }
          }
          //                    if(event.modelManager.getModel(inventory) !=
          // event.modelManager.getMissingModel()){
          //                        FMLLog.info("Model found @ " + inventory.toString() + ", this
          // means a resource pack is overriding it or a modder is doing something bad.
          // JSON-Destoyer will not attempt to create a model for it.");
          //                        continue;
          //                    }
          Function<ResourceLocation, TextureAtlasSprite> textureGetter;
          textureGetter =
              new Function<ResourceLocation, TextureAtlasSprite>() {
                public TextureAtlasSprite apply(ResourceLocation location) {
                  return Minecraft.getMinecraft()
                      .getTextureMapBlocks()
                      .getAtlasSprite(location.toString());
                }
              };
          ModelDynBucket modelDynBucket =
              new ModelDynBucket(
                  new ResourceLocation("forge:items/bucket_base"),
                  new ResourceLocation("forge:items/bucket_fluid"),
                  new ResourceLocation("forge:items/bucket_cover"),
                  iTexturedBucket.getFluid(i),
                  iTexturedBucket.isGas(i));

          IBakedModel model =
              modelDynBucket.bake(
                  ItemLayerModel.instance.getDefaultState(),
                  DefaultVertexFormats.ITEM,
                  textureGetter);
          itemModelMesher.register(item, i, inventory);
          event.modelRegistry.putObject(inventory, model);
        }
      }
    }
  }
  @SuppressWarnings("unchecked")
  public static void initVanillaEntries() {
    if (!hasInit) {
      registerOre("logWood", new ItemStack(Blocks.log, 1, WILDCARD_VALUE));
      registerOre("logWood", new ItemStack(Blocks.log2, 1, WILDCARD_VALUE));
      registerOre("plankWood", new ItemStack(Blocks.planks, 1, WILDCARD_VALUE));
      registerOre("slabWood", new ItemStack(Blocks.wooden_slab, 1, WILDCARD_VALUE));
      registerOre("stairWood", Blocks.oak_stairs);
      registerOre("stairWood", Blocks.spruce_stairs);
      registerOre("stairWood", Blocks.birch_stairs);
      registerOre("stairWood", Blocks.jungle_stairs);
      registerOre("stairWood", Blocks.acacia_stairs);
      registerOre("stairWood", Blocks.dark_oak_stairs);
      registerOre("stickWood", Items.stick);
      registerOre("treeSapling", new ItemStack(Blocks.sapling, 1, WILDCARD_VALUE));
      registerOre("treeLeaves", new ItemStack(Blocks.leaves, 1, WILDCARD_VALUE));
      registerOre("treeLeaves", new ItemStack(Blocks.leaves2, 1, WILDCARD_VALUE));
      registerOre("oreGold", Blocks.gold_ore);
      registerOre("oreIron", Blocks.iron_ore);
      registerOre("oreLapis", Blocks.lapis_ore);
      registerOre("oreDiamond", Blocks.diamond_ore);
      registerOre("oreRedstone", Blocks.redstone_ore);
      registerOre("oreEmerald", Blocks.emerald_ore);
      registerOre("oreQuartz", Blocks.quartz_ore);
      registerOre("oreCoal", Blocks.coal_ore);
      registerOre("blockGold", Blocks.gold_block);
      registerOre("blockIron", Blocks.iron_block);
      registerOre("blockLapis", Blocks.lapis_block);
      registerOre("blockDiamond", Blocks.diamond_block);
      registerOre("blockRedstone", Blocks.redstone_block);
      registerOre("blockEmerald", Blocks.emerald_block);
      registerOre("blockQuartz", Blocks.quartz_block);
      registerOre("blockCoal", Blocks.coal_block);
      registerOre("blockGlassColorless", Blocks.glass);
      registerOre("blockGlass", Blocks.glass);
      registerOre("blockGlass", new ItemStack(Blocks.stained_glass, 1, WILDCARD_VALUE));
      // blockGlass{Color} is added below with dyes
      registerOre("paneGlassColorless", Blocks.glass_pane);
      registerOre("paneGlass", Blocks.glass_pane);
      registerOre("paneGlass", new ItemStack(Blocks.stained_glass_pane, 1, WILDCARD_VALUE));
      // paneGlass{Color} is added below with dyes
      registerOre("ingotIron", Items.iron_ingot);
      registerOre("ingotGold", Items.gold_ingot);
      registerOre("ingotBrick", Items.brick);
      registerOre("ingotBrickNether", Items.netherbrick);
      registerOre("nuggetGold", Items.gold_nugget);
      registerOre("gemDiamond", Items.diamond);
      registerOre("gemEmerald", Items.emerald);
      registerOre("gemQuartz", Items.quartz);
      registerOre("dustRedstone", Items.redstone);
      registerOre("dustGlowstone", Items.glowstone_dust);
      registerOre("gemLapis", new ItemStack(Items.dye, 1, 4));
      registerOre("slimeball", Items.slime_ball);
      registerOre("glowstone", Blocks.glowstone);
      registerOre("cropWheat", Items.wheat);
      registerOre("cropPotato", Items.potato);
      registerOre("cropCarrot", Items.carrot);
      registerOre("stone", Blocks.stone);
      registerOre("cobblestone", Blocks.cobblestone);
      registerOre("sandstone", new ItemStack(Blocks.sandstone, 1, WILDCARD_VALUE));
      registerOre("sand", new ItemStack(Blocks.sand, 1, WILDCARD_VALUE));
      registerOre("dye", new ItemStack(Items.dye, 1, WILDCARD_VALUE));
      registerOre("record", Items.record_13);
      registerOre("record", Items.record_cat);
      registerOre("record", Items.record_blocks);
      registerOre("record", Items.record_chirp);
      registerOre("record", Items.record_far);
      registerOre("record", Items.record_mall);
      registerOre("record", Items.record_mellohi);
      registerOre("record", Items.record_stal);
      registerOre("record", Items.record_strad);
      registerOre("record", Items.record_ward);
      registerOre("record", Items.record_11);
      registerOre("record", Items.record_wait);
      registerOre("chest", Blocks.chest);
      registerOre("chest", Blocks.ender_chest);
      registerOre("chest", Blocks.trapped_chest);
      registerOre("chestWood", Blocks.chest);
      registerOre("chestEnder", Blocks.ender_chest);
      registerOre("chestTrapped", Blocks.trapped_chest);
    }

    // Build our list of items to replace with ore tags
    Map<ItemStack, String> replacements = new HashMap<ItemStack, String>();
    replacements.put(new ItemStack(Items.stick), "stickWood");
    replacements.put(new ItemStack(Blocks.planks), "plankWood");
    replacements.put(new ItemStack(Blocks.planks, 1, WILDCARD_VALUE), "plankWood");
    replacements.put(new ItemStack(Blocks.wooden_slab, 1, WILDCARD_VALUE), "slabWood");
    replacements.put(new ItemStack(Blocks.stone), "stone");
    // replacements.put(new ItemStack(Blocks.stone, 1, WILDCARD_VALUE), "stone");
    replacements.put(new ItemStack(Blocks.cobblestone), "cobblestone");
    replacements.put(new ItemStack(Blocks.cobblestone, 1, WILDCARD_VALUE), "cobblestone");
    replacements.put(new ItemStack(Items.gold_ingot), "ingotGold");
    replacements.put(new ItemStack(Items.iron_ingot), "ingotIron");
    replacements.put(new ItemStack(Items.diamond), "gemDiamond");
    replacements.put(new ItemStack(Items.emerald), "gemEmerald");
    replacements.put(new ItemStack(Items.redstone), "dustRedstone");
    replacements.put(new ItemStack(Items.glowstone_dust), "dustGlowstone");
    replacements.put(new ItemStack(Blocks.glowstone), "glowstone");
    replacements.put(new ItemStack(Items.slime_ball), "slimeball");
    replacements.put(new ItemStack(Blocks.glass), "blockGlassColorless");
    replacements.put(new ItemStack(Blocks.chest), "chestWood");
    replacements.put(new ItemStack(Blocks.ender_chest), "chestEnder");
    replacements.put(new ItemStack(Blocks.trapped_chest), "chestTrapped");

    // Register dyes
    String[] dyes = {
      "Black",
      "Red",
      "Green",
      "Brown",
      "Blue",
      "Purple",
      "Cyan",
      "LightGray",
      "Gray",
      "Pink",
      "Lime",
      "Yellow",
      "LightBlue",
      "Magenta",
      "Orange",
      "White"
    };

    for (int i = 0; i < 16; i++) {
      ItemStack dye = new ItemStack(Items.dye, 1, i);
      ItemStack block = new ItemStack(Blocks.stained_glass, 1, 15 - i);
      ItemStack pane = new ItemStack(Blocks.stained_glass_pane, 1, 15 - i);
      if (!hasInit) {
        registerOre("dye" + dyes[i], dye);
        registerOre("blockGlass" + dyes[i], block);
        registerOre("paneGlass" + dyes[i], pane);
      }
      replacements.put(dye, "dye" + dyes[i]);
      replacements.put(block, "blockGlass" + dyes[i]);
      replacements.put(pane, "paneGlass" + dyes[i]);
    }
    hasInit = true;

    ItemStack[] replaceStacks =
        replacements.keySet().toArray(new ItemStack[replacements.keySet().size()]);

    // Ignore recipes for the following items
    ItemStack[] exclusions =
        new ItemStack[] {
          new ItemStack(Blocks.lapis_block),
          new ItemStack(Items.cookie),
          new ItemStack(Blocks.stonebrick),
          new ItemStack(Blocks.stone_slab, 1, WILDCARD_VALUE),
          new ItemStack(Blocks.stone_stairs),
          new ItemStack(Blocks.cobblestone_wall),
          new ItemStack(Blocks.oak_fence),
          new ItemStack(Blocks.oak_fence_gate),
          new ItemStack(Blocks.oak_stairs),
          new ItemStack(Blocks.spruce_fence),
          new ItemStack(Blocks.spruce_fence_gate),
          new ItemStack(Blocks.spruce_stairs),
          new ItemStack(Blocks.birch_fence),
          new ItemStack(Blocks.birch_fence_gate),
          new ItemStack(Blocks.birch_stairs),
          new ItemStack(Blocks.jungle_fence),
          new ItemStack(Blocks.jungle_fence_gate),
          new ItemStack(Blocks.jungle_stairs),
          new ItemStack(Blocks.acacia_fence),
          new ItemStack(Blocks.acacia_fence_gate),
          new ItemStack(Blocks.acacia_stairs),
          new ItemStack(Blocks.dark_oak_fence),
          new ItemStack(Blocks.dark_oak_fence_gate),
          new ItemStack(Blocks.dark_oak_stairs),
          new ItemStack(Blocks.wooden_slab),
          new ItemStack(Blocks.glass_pane),
          null // So the above can have a comma and we don't have to keep editing extra lines.
        };

    List<IRecipe> recipes = CraftingManager.getInstance().getRecipeList();
    List<IRecipe> recipesToRemove = new ArrayList<IRecipe>();
    List<IRecipe> recipesToAdd = new ArrayList<IRecipe>();

    // Search vanilla recipes for recipes to replace
    for (Object obj : recipes) {
      if (obj instanceof ShapedRecipes) {
        ShapedRecipes recipe = (ShapedRecipes) obj;
        ItemStack output = recipe.getRecipeOutput();
        if (output != null && containsMatch(false, exclusions, output)) {
          continue;
        }

        if (containsMatch(true, recipe.recipeItems, replaceStacks)) {
          recipesToRemove.add(recipe);
          recipesToAdd.add(new ShapedOreRecipe(recipe, replacements));
        }
      } else if (obj instanceof ShapelessRecipes) {
        ShapelessRecipes recipe = (ShapelessRecipes) obj;
        ItemStack output = recipe.getRecipeOutput();
        if (output != null && containsMatch(false, exclusions, output)) {
          continue;
        }

        if (containsMatch(
            true,
            (ItemStack[]) recipe.recipeItems.toArray(new ItemStack[recipe.recipeItems.size()]),
            replaceStacks)) {
          recipesToRemove.add((IRecipe) obj);
          IRecipe newRecipe = new ShapelessOreRecipe(recipe, replacements);
          recipesToAdd.add(newRecipe);
        }
      }
    }

    recipes.removeAll(recipesToRemove);
    recipes.addAll(recipesToAdd);
    if (recipesToRemove.size() > 0) {
      FMLLog.info("Replaced %d ore recipies", recipesToRemove.size());
    }
  }
  private static void initVanillaEntries() {
    if (!hasInit) {
      // tree- and wood-related things
      registerOre("logWood", new ItemStack(Blocks.log, 1, WILDCARD_VALUE));
      registerOre("logWood", new ItemStack(Blocks.log2, 1, WILDCARD_VALUE));
      registerOre("plankWood", new ItemStack(Blocks.planks, 1, WILDCARD_VALUE));
      registerOre("slabWood", new ItemStack(Blocks.wooden_slab, 1, WILDCARD_VALUE));
      registerOre("stairWood", Blocks.oak_stairs);
      registerOre("stairWood", Blocks.spruce_stairs);
      registerOre("stairWood", Blocks.birch_stairs);
      registerOre("stairWood", Blocks.jungle_stairs);
      registerOre("stairWood", Blocks.acacia_stairs);
      registerOre("stairWood", Blocks.dark_oak_stairs);
      registerOre("stickWood", Items.stick);
      registerOre("treeSapling", new ItemStack(Blocks.sapling, 1, WILDCARD_VALUE));
      registerOre("treeLeaves", new ItemStack(Blocks.leaves, 1, WILDCARD_VALUE));
      registerOre("treeLeaves", new ItemStack(Blocks.leaves2, 1, WILDCARD_VALUE));
      registerOre("vine", Blocks.vine);

      // Ores
      registerOre("oreGold", Blocks.gold_ore);
      registerOre("oreIron", Blocks.iron_ore);
      registerOre("oreLapis", Blocks.lapis_ore);
      registerOre("oreDiamond", Blocks.diamond_ore);
      registerOre("oreRedstone", Blocks.redstone_ore);
      registerOre("oreEmerald", Blocks.emerald_ore);
      registerOre("oreQuartz", Blocks.quartz_ore);
      registerOre("oreCoal", Blocks.coal_ore);

      // ingots/nuggets
      registerOre("ingotIron", Items.iron_ingot);
      registerOre("ingotGold", Items.gold_ingot);
      registerOre("ingotBrick", Items.brick);
      registerOre("ingotBrickNether", Items.netherbrick);
      registerOre("nuggetGold", Items.gold_nugget);

      // gems and dusts
      registerOre("gemDiamond", Items.diamond);
      registerOre("gemEmerald", Items.emerald);
      registerOre("gemQuartz", Items.quartz);
      registerOre("gemPrismarine", Items.prismarine_shard);
      registerOre("dustPrismarine", Items.prismarine_crystals);
      registerOre("dustRedstone", Items.redstone);
      registerOre("dustGlowstone", Items.glowstone_dust);
      registerOre("gemLapis", new ItemStack(Items.dye, 1, 4));

      // storage blocks
      registerOre("blockGold", Blocks.gold_block);
      registerOre("blockIron", Blocks.iron_block);
      registerOre("blockLapis", Blocks.lapis_block);
      registerOre("blockDiamond", Blocks.diamond_block);
      registerOre("blockRedstone", Blocks.redstone_block);
      registerOre("blockEmerald", Blocks.emerald_block);
      registerOre("blockQuartz", Blocks.quartz_block);
      registerOre("blockCoal", Blocks.coal_block);

      // crops
      registerOre("cropWheat", Items.wheat);
      registerOre("cropPotato", Items.potato);
      registerOre("cropCarrot", Items.carrot);
      registerOre("cropNetherWart", Items.nether_wart);
      registerOre("sugarcane", Items.reeds);
      registerOre("blockCactus", Blocks.cactus);

      // misc materials
      registerOre("dye", new ItemStack(Items.dye, 1, WILDCARD_VALUE));
      registerOre("paper", new ItemStack(Items.paper));

      // mob drops
      registerOre("slimeball", Items.slime_ball);
      registerOre("enderpearl", Items.ender_pearl);
      registerOre("bone", Items.bone);
      registerOre("gunpowder", Items.gunpowder);
      registerOre("string", Items.string);
      registerOre("netherStar", Items.nether_star);
      registerOre("leather", Items.leather);
      registerOre("feather", Items.feather);
      registerOre("egg", Items.egg);

      // records
      registerOre("record", Items.record_13);
      registerOre("record", Items.record_cat);
      registerOre("record", Items.record_blocks);
      registerOre("record", Items.record_chirp);
      registerOre("record", Items.record_far);
      registerOre("record", Items.record_mall);
      registerOre("record", Items.record_mellohi);
      registerOre("record", Items.record_stal);
      registerOre("record", Items.record_strad);
      registerOre("record", Items.record_ward);
      registerOre("record", Items.record_11);
      registerOre("record", Items.record_wait);

      // blocks
      registerOre("dirt", Blocks.dirt);
      registerOre("grass", Blocks.grass);
      registerOre("stone", Blocks.stone);
      registerOre("cobblestone", Blocks.cobblestone);
      registerOre("gravel", Blocks.gravel);
      registerOre("sand", new ItemStack(Blocks.sand, 1, WILDCARD_VALUE));
      registerOre("sandstone", new ItemStack(Blocks.sandstone, 1, WILDCARD_VALUE));
      registerOre("sandstone", new ItemStack(Blocks.red_sandstone, 1, WILDCARD_VALUE));
      registerOre("netherrack", Blocks.netherrack);
      registerOre("obsidian", Blocks.obsidian);
      registerOre("glowstone", Blocks.glowstone);
      registerOre("endstone", Blocks.end_stone);
      registerOre("torch", Blocks.torch);
      registerOre("workbench", Blocks.crafting_table);
      registerOre("blockSlime", Blocks.slime_block);
      registerOre(
          "blockPrismarine",
          new ItemStack(Blocks.prismarine, 1, BlockPrismarine.EnumType.ROUGH.getMetadata()));
      registerOre(
          "blockPrismarineBrick",
          new ItemStack(Blocks.prismarine, 1, BlockPrismarine.EnumType.BRICKS.getMetadata()));
      registerOre(
          "blockPrismarineDark",
          new ItemStack(Blocks.prismarine, 1, BlockPrismarine.EnumType.DARK.getMetadata()));
      registerOre("stoneGranite", new ItemStack(Blocks.stone, 1, 1));
      registerOre("stoneGranitePolished", new ItemStack(Blocks.stone, 1, 2));
      registerOre("stoneDiorite", new ItemStack(Blocks.stone, 1, 3));
      registerOre("stoneDioritePolished", new ItemStack(Blocks.stone, 1, 4));
      registerOre("stoneAndesite", new ItemStack(Blocks.stone, 1, 5));
      registerOre("stoneAndesitePolished", new ItemStack(Blocks.stone, 1, 6));
      registerOre("blockGlassColorless", Blocks.glass);
      registerOre("blockGlass", Blocks.glass);
      registerOre("blockGlass", new ItemStack(Blocks.stained_glass, 1, WILDCARD_VALUE));
      // blockGlass{Color} is added below with dyes
      registerOre("paneGlassColorless", Blocks.glass_pane);
      registerOre("paneGlass", Blocks.glass_pane);
      registerOre("paneGlass", new ItemStack(Blocks.stained_glass_pane, 1, WILDCARD_VALUE));
      // paneGlass{Color} is added below with dyes

      // chests
      registerOre("chest", Blocks.chest);
      registerOre("chest", Blocks.ender_chest);
      registerOre("chest", Blocks.trapped_chest);
      registerOre("chestWood", Blocks.chest);
      registerOre("chestEnder", Blocks.ender_chest);
      registerOre("chestTrapped", Blocks.trapped_chest);
    }

    // Build our list of items to replace with ore tags
    Map<ItemStack, String> replacements = new HashMap<ItemStack, String>();

    // wood-related things
    replacements.put(new ItemStack(Items.stick), "stickWood");
    replacements.put(new ItemStack(Blocks.planks), "plankWood");
    replacements.put(new ItemStack(Blocks.planks, 1, WILDCARD_VALUE), "plankWood");
    replacements.put(new ItemStack(Blocks.wooden_slab, 1, WILDCARD_VALUE), "slabWood");

    // ingots/nuggets
    replacements.put(new ItemStack(Items.gold_ingot), "ingotGold");
    replacements.put(new ItemStack(Items.iron_ingot), "ingotIron");

    // gems and dusts
    replacements.put(new ItemStack(Items.diamond), "gemDiamond");
    replacements.put(new ItemStack(Items.emerald), "gemEmerald");
    replacements.put(new ItemStack(Items.prismarine_shard), "gemPrismarine");
    replacements.put(new ItemStack(Items.prismarine_crystals), "dustPrismarine");
    replacements.put(new ItemStack(Items.redstone), "dustRedstone");
    replacements.put(new ItemStack(Items.glowstone_dust), "dustGlowstone");

    // crops
    replacements.put(new ItemStack(Items.reeds), "sugarcane");
    replacements.put(new ItemStack(Blocks.cactus), "blockCactus");

    // misc materials
    replacements.put(new ItemStack(Items.paper), "paper");

    // mob drops
    replacements.put(new ItemStack(Items.slime_ball), "slimeball");
    replacements.put(new ItemStack(Items.string), "string");
    replacements.put(new ItemStack(Items.leather), "leather");
    replacements.put(new ItemStack(Items.ender_pearl), "enderpearl");
    replacements.put(new ItemStack(Items.gunpowder), "gunpowder");
    replacements.put(new ItemStack(Items.nether_star), "netherStar");
    replacements.put(new ItemStack(Items.feather), "feather");
    replacements.put(new ItemStack(Items.bone), "bone");
    replacements.put(new ItemStack(Items.egg), "egg");

    // blocks
    replacements.put(new ItemStack(Blocks.stone), "stone");
    replacements.put(new ItemStack(Blocks.cobblestone), "cobblestone");
    replacements.put(new ItemStack(Blocks.cobblestone, 1, WILDCARD_VALUE), "cobblestone");
    replacements.put(new ItemStack(Blocks.glowstone), "glowstone");
    replacements.put(new ItemStack(Blocks.glass), "blockGlassColorless");
    replacements.put(new ItemStack(Blocks.prismarine), "prismarine");
    replacements.put(new ItemStack(Blocks.stone, 1, 1), "stoneGranite");
    replacements.put(new ItemStack(Blocks.stone, 1, 2), "stoneGranitePolished");
    replacements.put(new ItemStack(Blocks.stone, 1, 3), "stoneDiorite");
    replacements.put(new ItemStack(Blocks.stone, 1, 4), "stoneDioritePolished");
    replacements.put(new ItemStack(Blocks.stone, 1, 5), "stoneAndesite");
    replacements.put(new ItemStack(Blocks.stone, 1, 6), "stoneAndesitePolished");

    // chests
    replacements.put(new ItemStack(Blocks.chest), "chestWood");
    replacements.put(new ItemStack(Blocks.ender_chest), "chestEnder");
    replacements.put(new ItemStack(Blocks.trapped_chest), "chestTrapped");

    // Register dyes
    String[] dyes = {
      "Black",
      "Red",
      "Green",
      "Brown",
      "Blue",
      "Purple",
      "Cyan",
      "LightGray",
      "Gray",
      "Pink",
      "Lime",
      "Yellow",
      "LightBlue",
      "Magenta",
      "Orange",
      "White"
    };

    for (int i = 0; i < 16; i++) {
      ItemStack dye = new ItemStack(Items.dye, 1, i);
      ItemStack block = new ItemStack(Blocks.stained_glass, 1, 15 - i);
      ItemStack pane = new ItemStack(Blocks.stained_glass_pane, 1, 15 - i);
      if (!hasInit) {
        registerOre("dye" + dyes[i], dye);
        registerOre("blockGlass" + dyes[i], block);
        registerOre("paneGlass" + dyes[i], pane);
      }
      replacements.put(dye, "dye" + dyes[i]);
      replacements.put(block, "blockGlass" + dyes[i]);
      replacements.put(pane, "paneGlass" + dyes[i]);
    }
    hasInit = true;

    ItemStack[] replaceStacks =
        replacements.keySet().toArray(new ItemStack[replacements.keySet().size()]);

    // Ignore recipes for the following items
    ItemStack[] exclusions =
        new ItemStack[] {
          new ItemStack(Blocks.lapis_block),
          new ItemStack(Items.cookie),
          new ItemStack(Blocks.stonebrick),
          new ItemStack(Blocks.stone_slab, 1, WILDCARD_VALUE),
          new ItemStack(Blocks.stone_stairs),
          new ItemStack(Blocks.cobblestone_wall),
          new ItemStack(Blocks.oak_fence),
          new ItemStack(Blocks.oak_fence_gate),
          new ItemStack(Blocks.oak_stairs),
          new ItemStack(Blocks.spruce_fence),
          new ItemStack(Blocks.spruce_fence_gate),
          new ItemStack(Blocks.spruce_stairs),
          new ItemStack(Blocks.birch_fence),
          new ItemStack(Blocks.birch_fence_gate),
          new ItemStack(Blocks.birch_stairs),
          new ItemStack(Blocks.jungle_fence),
          new ItemStack(Blocks.jungle_fence_gate),
          new ItemStack(Blocks.jungle_stairs),
          new ItemStack(Blocks.acacia_fence),
          new ItemStack(Blocks.acacia_fence_gate),
          new ItemStack(Blocks.acacia_stairs),
          new ItemStack(Blocks.dark_oak_fence),
          new ItemStack(Blocks.dark_oak_fence_gate),
          new ItemStack(Blocks.dark_oak_stairs),
          new ItemStack(Blocks.wooden_slab),
          new ItemStack(Blocks.glass_pane),
          null // So the above can have a comma and we don't have to keep editing extra lines.
        };

    List<IRecipe> recipes = CraftingManager.getInstance().getRecipeList();
    List<IRecipe> recipesToRemove = new ArrayList<IRecipe>();
    List<IRecipe> recipesToAdd = new ArrayList<IRecipe>();

    // Search vanilla recipes for recipes to replace
    for (Object obj : recipes) {
      if (obj instanceof ShapedRecipes) {
        ShapedRecipes recipe = (ShapedRecipes) obj;
        ItemStack output = recipe.getRecipeOutput();
        if (output != null && containsMatch(false, exclusions, output)) {
          continue;
        }

        if (containsMatch(true, recipe.recipeItems, replaceStacks)) {
          recipesToRemove.add(recipe);
          recipesToAdd.add(new ShapedOreRecipe(recipe, replacements));
        }
      } else if (obj instanceof ShapelessRecipes) {
        ShapelessRecipes recipe = (ShapelessRecipes) obj;
        ItemStack output = recipe.getRecipeOutput();
        if (output != null && containsMatch(false, exclusions, output)) {
          continue;
        }

        if (containsMatch(
            true,
            recipe.recipeItems.toArray(new ItemStack[recipe.recipeItems.size()]),
            replaceStacks)) {
          recipesToRemove.add((IRecipe) obj);
          IRecipe newRecipe = new ShapelessOreRecipe(recipe, replacements);
          recipesToAdd.add(newRecipe);
        }
      }
    }

    recipes.removeAll(recipesToRemove);
    recipes.addAll(recipesToAdd);
    if (recipesToRemove.size() > 0) {
      FMLLog.info("Replaced %d ore recipes", recipesToRemove.size());
    }
  }