public static void initNotLearnables() {
    for (String oreName : OreDictionary.getOreNames()) {
      if (oreName.startsWith("ore")) {
        for (ItemStack itemStack :
            CachedOreDictionary.getInstance().getItemStacksForOreName(oreName)) {
          AbilityRegistryProxy.setAsNotLearnable(itemStack);
        }
        AbilityRegistryProxy.setAsNotLearnable(new OreStack(oreName));
      }
    }
    AbilityRegistryProxy.setAsNotLearnable(new ItemStack(Blocks.coal_ore));

    AbilityRegistryProxy.setAsNotLearnable(ModItems.shardMinium);
    AbilityRegistryProxy.setAsNotLearnable(new ItemStack(ModItems.alchemicalDust, 1, 1));
    AbilityRegistryProxy.setAsNotLearnable(new ItemStack(ModItems.alchemicalDust, 1, 2));
  }
  @Override
  public List<IOreDictEntry> getOres() {
    List<IOreDictEntry> result = new ArrayList<>();

    for (String key : OreDictionary.getOreNames()) {
      for (ItemStack is : OreDictionary.getOres(key)) {
        if (is.getItem() == stack.getItem()
            && (is.getItemDamage() == OreDictionary.WILDCARD_VALUE
                || is.getItemDamage() == stack.getItemDamage())) {
          result.add(MineTweakerAPI.oreDict.get(key));
          break;
        }
      }
    }

    return result;
  }
  @Override
  public void processCommand(ICommandSender icommandsender, String[] astring) {
    File file = new File("dump_OreDict.txt");
    try {
      PrintWriter pw = new PrintWriter(file);
      for (String ore : OreDictionary.getOreNames()) pw.println(ore);

      pw.close();

      icommandsender.addChatMessage(
          new ChatComponentText("Dumped oredict names to " + file.getName()));
    } catch (FileNotFoundException e) {
      Log.error("Couldn't create file " + file.getName());
      icommandsender.addChatMessage(
          new ChatComponentText("Couldn't create file " + file.getName()));
    }
  }
  private void updateStackList(String oreName) {
    if (iterStacks == null) {
      iterStacks = new ArrayList<ItemStack>();
    } else {
      iterStacks.clear();
    }

    List<String> keys = new ArrayList<String>();

    for (String s : OreDictionary.getOreNames()) {
      if (oreName.equals(s) || oreName.equals("*")) {
        keys.add(s);
      } else if (oreName.endsWith("*") && !oreName.startsWith("*")) {
        if (s.startsWith(oreName.substring(0, oreName.length() - 1))) {
          keys.add(s);
        }
      } else if (oreName.startsWith("*") && !oreName.endsWith("*")) {
        if (s.endsWith(oreName.substring(1))) {
          keys.add(s);
        }
      } else if (oreName.startsWith("*") && oreName.endsWith("*")) {
        if (s.contains(oreName.substring(1, oreName.length() - 1))) {
          keys.add(s);
        }
      }
    }

    for (String key : keys) {
      for (ItemStack stack : OreDictionary.getOres(key)) {
        ItemStack toAdd = stack.copy();

        if (!iterStacks.contains(stack) && toAdd.getItem() instanceof ItemBlock) {
          iterStacks.add(stack.copy());
        }
      }
    }

    stackSwitch = 0;
    stackIndex = -1;
  }
  @Override
  public NBTTagCompound getNBTFromRecipe(ShapedOreRecipe recipe, ItemStack newOutput)
      throws IllegalAccessException {
    NBTTagCompound nbtRecipe = new NBTTagCompound();
    NBTTagList NBTInput = new NBTTagList();

    int width = ShapedOreRecipe_width.getInt(recipe);
    int height = ShapedOreRecipe_height.getInt(recipe);

    /** Build a map to convert the object array into recipe format. */
    HashBiMap<Character, Object> map = HashBiMap.create();
    HashMap<ArrayList, Object> arrayListMap =
        new HashMap<ArrayList, Object>(); // Lookup map for oredict entries.
    for (Object o : recipe.getInput()) {
      if (o == null) continue;
      if (map.containsValue(o)) continue;
      if (o instanceof ArrayList) {
        for (String name : OreDictionary.getOreNames()) {
          if (OreDictionary.getOres(name).equals(o)) {
            if (map.containsValue(name)) break;
            map.put(DUMMY_CHARS.charAt(map.size()), name);
            arrayListMap.put((ArrayList) o, name);
            break;
          }
        }
      } else {
        map.put(DUMMY_CHARS.charAt(map.size()), o);
      }
    }

    /** Make the recipe strings aka: "aa ", "aa ", "aa " */
    char[][] chars = new char[height][width];
    for (int h = 0; h < height; h++) {
      for (int w = 0; w < width; w++) {
        int i = h * width + w;
        if (recipe.getInput()[i] == null) chars[h][w] = ' ';
        else if (recipe.getInput()[i] instanceof ArrayList)
          chars[h][w] = map.inverse().get(arrayListMap.get(recipe.getInput()[i]));
        else chars[h][w] = map.inverse().get(recipe.getInput()[i]);
      }
      String line = new String(chars[h]);
      NBTInput.appendTag(new NBTTagString(null, line));
    }
    nbtRecipe.setTag(NBT_input, NBTInput);

    /** Add the char to itemstack thing aka: 'a' = "plank" */
    NBTTagCompound nbtMap = new NBTTagCompound();
    for (Map.Entry<Character, Object> entry : map.entrySet()) {
      if (entry.getValue() instanceof String)
        nbtMap.setString(entry.getKey().toString(), entry.getValue().toString());
      else if (entry.getValue() instanceof ItemStack)
        nbtMap.setCompoundTag(
            entry.getKey().toString(),
            ((ItemStack) entry.getValue()).writeToNBT(new NBTTagCompound()));
      else {
        CrayCrafting.logger.severe(
            "NBT RECIPE ERROR: " + entry.getValue() + " IS NOT STRING OR ITEMSTACK ???");
      }
    }
    nbtRecipe.setCompoundTag(NBT_map, nbtMap);
    nbtRecipe.setCompoundTag(NBT_output, newOutput.writeToNBT(new NBTTagCompound()));
    nbtRecipe.setBoolean(NBT_mirror, ShapedOreRecipe_mirror.getBoolean(recipe));

    return nbtRecipe;
  }