public class Ores {
	private static Ores instance = new Ores();
	
	public static IOreManager manager;
	
	public static IOreFluidManager fluidManager;
	
	public static IOreRecipeManager grinderRecipes;
	public static IOreFluidRecipeManager crackerRecipes;

	private Ores () {}
	
	private class BlockInfo {
		public String ownerMod;
		public Block block;
		
		public BlockInfo(String owner, Block newBlock) {
			this.ownerMod = owner;
			this.block = newBlock;
		}

	}
	
	
} public class BlockCore extends net.minecraft.block.Block {
	public BlockCore(Material material, String blockName, boolean isMeta) {
		super(material);
		this.setBlockName(blockName); // name
		this.setBlockTextureName(References.MOD_ID +":" + blockName); // texture
		if (isMeta)
			GameRegistry.registerBlock(this, ItemBlockWithMetadata.class, blockName);
		else
			GameRegistry.registerBlock(this, blockName);
	}

	public BlockCore(Material material, String blockName) {
		this(material, blockName, false);
	}
} public class BlockOre extends BlockCore {
	private OreDrops drops;
	private int xpDropLow;
	private int xpDropHigh;
	private boolean _isNether;
	
	public BlockOre(OreClass ore, boolean isNether) {
		super (Material.rock, ore.name);
		this.drops = ore.drops;
		this.setCreativeTab(CreativeTabs.tabBlock);
		OreDictionary.registerOre(ore.name, this);
		this.setHardness(3.0F);
		this.setHarvestLevel("pickaxe", ore.harvestLevel);
		this.xpDropLow = ore.xpDropLow;
		this.xpDropHigh = ore.xpDropHigh;
		this._isNether = isNether;
		Ores.manager.registerOre(ore.name, this);
	}
	
	public BlockOre(OreClass ore) {
		this(ore, false);
	}

	private Random rand = new Random();
    @Override
    public int getExpDrop(IBlockAccess var1, int var2, int var3) {
    	if (this.xpDropLow == 0 && this.xpDropHigh == 0)
    		return 0;
    	else
    		return this.xpDropLow + rand.nextInt(this.xpDropHigh - this.xpDropLow + 1);
    }
    
	@Override
    public ArrayList<ItemStack> getDrops(World world, int x, int y, int z, int metadata, int fortune) {
		ArrayList rList = new ArrayList();
		switch (this.drops)	{
		case AMETHYST:
			rList.add(GemstoneOres.Amethyst.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case APATITE:
			rList.add(GemstoneOres.Apatite.gem.newStack(this.fortuneHelper(world, 1 + world.rand.nextInt(4), fortune)));
			break;
		case BITUMEN:
			rList.add(Items.itemBitumen.item.newStack(this.fortuneHelper(world, 2 + world.rand.nextInt(4), fortune)));
			break;
		case CERTUSQUARTZ:
			Item certusQuartz = Helpers.AppliedEnergistics.getItem("item.ItemMultiMaterial");
			if (Helpers.AppliedEnergistics.isLoaded() && certusQuartz != null) {
				OreItemStack cqStack = world.rand.nextFloat() > 0.92F ? 
					new OreItemStack(new ItemStack(certusQuartz, 1, 1)) :
					new OreItemStack(new ItemStack(certusQuartz, 1, 0));
				rList.add(cqStack.newStack(fortuneHelper(world, 1 + world.rand.nextInt(2), fortune)));
			}
			else {
				rList.add(new ItemStack(this.getItemDropped(metadata, world.rand, fortune), 1));
			}
			break;
		case CINNABAR: // cinnabar = 1 cinnabar & 1/4 redstone (gregstech)
			rList.add(MineralOres.Cinnabar.dust.newStack(this.fortuneHelper(world, 1, fortune)));
			if (world.rand.nextInt(4) == 0)	{
				rList.add(new ItemStack(net.minecraft.init.Items.redstone, this.fortuneHelper(world, 1, fortune)));
			}
			break;
		case IRIDIUM: // iridium = 1 (half fortune) iridium (gregstech)
			rList.add(Items.gemIridium.item.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case MAGNESIUM: // magnesium = 2-5 magnesium (metallurgy)
			rList.add(Items.dustMagnesium.item.newStack(this.fortuneHelper(world, 2 + world.rand.nextInt(4), fortune)));
			break;
		case MALACHITE:
			rList.add(GemstoneOres.Malachite.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case NIKOLITE: // nikolite = 4-5 nikolite (rp2)
			rList.add(DustyOres.Nikolite.dust.newStack(this.fortuneHelper(world, 4 + world.rand.nextInt(2), fortune)));
			break;
		case OLIVINE:
			rList.add(Items.gemOlivine.item.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case PERIDOT:
			rList.add(GemstoneOres.Peridot.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case PHOSPHORITE: // phosphorite = 2-5 phosphorite (metallurgy)
			rList.add(DustyOres.Phosphorite.dust.newStack(this.fortuneHelper(world, 2 + world.rand.nextInt(4), fortune)));
			break;
		case POTASH: // potash = 2-5 potash (metallurgy)
			rList.add(DustyOres.Potash.dust.newStack(this.fortuneHelper(world, 2 + world.rand.nextInt(4), fortune)));
			break;
		case PYRITE: // pyrite = 1 pyrite (gregstech)
			rList.add(MineralOres.Pyrite.dust.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case RUBY: // ruby = 1 ruby (twstuff/rp2) | 1 ruby & 1/32 red garnet (gregstech)
			rList.add(GemstoneOres.Ruby.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			if (world.rand.nextInt(32) == 0) {
				rList.add(Items.gemRedGarnet.item.newStack(this.fortuneHelper(world, 1, fortune)));
			}
			break;
		case SALTPETER: // saltpeter = 1-2 saltpeter (railcraft) | 2-5 saltpeter (metallurgy)
			rList.add(DustyOres.Saltpeter.dust.newStack(this.fortuneHelper(world, 1 + world.rand.nextInt(2), fortune)));
			break;
		case SAPPHIRE: // sapphire = 1 sapphire (twstuff/rp2) | 1 sapphiree & 1/64 green sapphire
			rList.add(GemstoneOres.Sapphire.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			if (world.rand.nextInt(64) == 0) {
				rList.add(GemstoneOres.Peridot.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			}
			break;
		case SODALITE: // sodalite = 6 sodalite & 1/4 aluminium (gregstech)
			rList.add(Items.dustSodalite.item.newStack(this.fortuneHelper(world, 6, fortune)));
			if (world.rand.nextInt(4) == 0)	{
				rList.add(MetallicOres.Aluminium.dust.newStack(this.fortuneHelper(world, 1, fortune)));
			}
			break;
		case SPHALERITE: // sphalerite = 1 sphalerite & 1/4 zinc & 1/32 yellow garnet
			rList.add(MineralOres.Sphalerite.dust.newStack(this.fortuneHelper(world, 1, fortune)));
			if (world.rand.nextInt(4) == 0)	{
				rList.add(MetallicOres.Zinc.dust.newStack(this.fortuneHelper(world, 1, fortune)));
			}
			if (world.rand.nextInt(32) == 0) {
				rList.add(Items.gemYellowGarnet.item.newStack(this.fortuneHelper(world, 1, fortune)));
			}
			break;
		case SULFUR: // sulfur = 2-5 sulfur (railcraft/metallurgy)
			rList.add(DustyOres.Sulfur.dust.newStack(this.fortuneHelper(world, 2 + world.rand.nextInt(4), fortune)));
			break;
		case TANZANITE:
			rList.add(GemstoneOres.Tanzanite.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		case TOPAZ: // topaz = 1 topaz (twstuff)
			rList.add(GemstoneOres.Topaz.gem.newStack(this.fortuneHelper(world, 1, fortune)));
			break;
		default:
			rList.add(new ItemStack(this.getItemDropped(metadata, world.rand, fortune), 1));
		}
		return rList;
    }
	
	private int fortuneHelper(World world, int stackSize, int fortune) {
		switch (this.drops){
		case AMETHYST:
		case CERTUSQUARTZ:
		case CINNABAR:
		case PERIDOT:
		case IRIDIUM:
		case MALACHITE:
		case PYRITE:
		case RUBY:
		case SAPPHIRE:
		case SPHALERITE:
		case TANZANITE:
		case TOPAZ:
		case URANIUM:
			switch (fortune) {
			case 1:
				if (world.rand.nextInt(3) == 0)
					stackSize = stackSize * 2;
				break;
			case 2:
				switch (world.rand.nextInt(4)) {
				case 0:
					stackSize = stackSize * 2;
					break;
				case 1: 
					stackSize = stackSize * 3;
					break;
				}
				break;
			case 3:
				switch (world.rand.nextInt(5)) {
				case 0:
					stackSize = stackSize * 2;
					break;
				case 1:
					stackSize = stackSize * 3;
					break;
				case 2:
					stackSize = stackSize * 4;
					break;
				}
				break;
			}
			break;
		case APATITE:
		case BITUMEN:
		case MAGNESIUM:
		case NIKOLITE:
		case OLIVINE:
		case PHOSPHORITE:
		case POTASH:
		case SALTPETER:
		case SULFUR:
		case SODALITE:
			if (fortune >= 1)
				stackSize++;
			if (fortune >= 2)
				stackSize++;
			if (fortune == 3)
				stackSize++;
			break;
		default:
		}
		return stackSize;
	}

	@Override
    public void harvestBlock(World world, EntityPlayer player, int x, int y, int z, int meta) {
		super.harvestBlock(world, player, x, y, z, meta);
		if (OresPlus.angryPigmen & this._isNether)
			upsetThePigs(player, world, x, y, z);
	}

	private static void upsetThePigs(EntityPlayer player, World world, int x, int y, int z) {
		int range = 32;
		List entities = world.getEntitiesWithinAABB(net.minecraft.entity.monster.EntityPigZombie.class, AxisAlignedBB.getBoundingBox(x - range, y - range, z - range, x + range + 1, y  + range + 1, z + range + 1));
		
		for (Object entity : entities) {
			if (entity instanceof EntityPigZombie) {
				((EntityPigZombie)entity).attackEntityFrom(DamageSource.causePlayerDamage(player), 0);
			}
		}
	}
} public class BlockManager {
	private static boolean isInitialized = false;
	
	public static OreItemStack grinder;
	public static OreItemStack grinder_lit;
	public static OreItemStack cracker;
	public static OreItemStack cracker_lit;
	
	public static void init() {
		if (isInitialized) {
			OresPlus.log.info("Block initialization failed, already initialized");
			return;
		}
		OresPlus.log.info("Initializing Blocks");

		for (MetallicOres ore : MetallicOres.values()) {
			ore.registerBlocks();
		}
		
		for (GemstoneOres ore : GemstoneOres.values()) {
			ore.registerBlocks();
		}
		
		for (DustyOres ore : DustyOres.values()) {
			ore.registerBlocks();
		}
		
		for (MineralOres ore : MineralOres.values()) {
			ore.registerBlocks();
		}
		
		for (GeneralOres ore : GeneralOres.values()) {
			ore.registerBlocks();
		}
		
		//nAdditional Ore Dictionary Support
		OreDictionary.registerOre("oreYellorite", MetallicOres.Yellorium.ore.source);
		
		// register machine blocks
		grinder = new OreItemStack(new BlockGrinder(false));
		grinder_lit = new OreItemStack(new BlockGrinder(true));
		RecipeManager.hideItem(grinder_lit);
		
		cracker = new OreItemStack(new BlockCracker(false));
		cracker_lit = new OreItemStack(new BlockCracker(true));
		RecipeManager.hideItem(cracker_lit);
		
		// register vanilla ores for custom ore generators
		Ores.manager.registerOre("oreIron", net.minecraft.init.Blocks.iron_ore);
		Ores.manager.registerOre("oreGold", net.minecraft.init.Blocks.gold_ore);
		Ores.manager.registerOre("oreDiamond", net.minecraft.init.Blocks.diamond_ore);
		Ores.manager.registerOre("oreEmerald", net.minecraft.init.Blocks.emerald_ore);
		Ores.manager.registerOre("oreLapis",  net.minecraft.init.Blocks.lapis_ore);
		Ores.manager.registerOre("oreQuartz", net.minecraft.init.Blocks.quartz_ore);
		Ores.manager.registerOre("oreCoal", net.minecraft.init.Blocks.coal_ore);
		
		isInitialized=true;
	}
	
	public static void handleRemaps(FMLModIdMappingEvent event) {
		OresPlus.log.info("recieved remap event");
		
	}

	public static void registerAspects() {
	    ThaumcraftApi.registerObjectTag(cracker.source, new AspectList());
	    ThaumcraftApi.registerObjectTag(grinder.source, new AspectList());
	}
	
} public class TileEntityCracker extends TileEntityMachine {
    private static final int[] slotsTop = new int[] {0};
    private static final int[] slotsBottom = new int[] {1};
    private static final int[] slotsSides = new int[] {1};

	public TileEntityCracker() {
		super();
		this.inventory = new ItemStack[3];
		this.inventoryName = "container:cracker";
	}
	
	@Override
	public void readFromNBT(NBTTagCompound tag) {
		super.readFromNBT(tag);
	}
	
	@Override
	public void writeToNBT(NBTTagCompound tag) {
		super.writeToNBT(tag);
	}
	
	@Override
	public Packet getDescriptionPacket() {
		return NetHandler.INSTANCE.getPacketFrom(new PacketCracker(this));
	}
	
	@Override
	public void updateEntity() {
		super.updateEntity();
		
		if (!worldObj.isRemote) {
			if (this.ticker % 20 == 0) {
			}
		}
		NetHandler.INSTANCE.sendToAll(new PacketCracker(this));
	}
	
	@Override
	public boolean hasWork() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public int[] getAccessibleSlotsFromSide(int side) {
		return side == 0 ? slotsBottom : (side == 1 ? slotsTop : slotsSides);
	}

} public class TileEntityGrinder extends TileEntityMachine {
    private static final int[] slotsTop = new int[] {0};
    private static final int[] slotsBottom = new int[] {2, 1};
    private static final int[] slotsSides = new int[] {1};
    
	public TileEntityGrinder() {
		super();
		this.inventory = new ItemStack[4];
		this.inventoryName = "container:grinder";
	}
	
	@Override
	public void readFromNBT(NBTTagCompound tag) {
		super.readFromNBT(tag);
	}
	
	@Override
	public void writeToNBT(NBTTagCompound tag) {
		super.writeToNBT(tag);
	}
	
	@Override
	public Packet getDescriptionPacket() {
		return NetHandler.INSTANCE.getPacketFrom(new PacketGrinder(this));
	}
	
	@Override
	public void updateEntity() {
		super.updateEntity();
		
		if (!worldObj.isRemote) {
			if (this.ticker % 20 == 0) {
			}
		}
		NetHandler.INSTANCE.sendToAll(new PacketGrinder(this));
	}

	@Override
	public boolean hasWork() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public int[] getAccessibleSlotsFromSide(int side) {
		return side == 0 ? slotsBottom : (side == 1 ? slotsTop : slotsSides);
	}


} public class BucketHandler {
	//public static HashMap<Block, Item> bucketMap = new HashMap<Block, Item>();
	
	@SubscribeEvent
	public void onFillBucket(FillBucketEvent event) {
		if (event.current.getItem() instanceof OreBucket) {
			/*
			if (event.target == null) {
				return;
			}
			else {
				int clickX = event.target.blockX;
				int clickY = event.target.blockY;
				int clickZ = event.target.blockZ;
				
				if (!event.world.canMineBlock(event.entityPlayer, clickX, clickY, clickZ)) {
					return;
				}
				
				switch (event.target.sideHit) {
				case 0:
					--clickY;
					break;
				case 1:
					++clickY;
					break;
				case 2:
					--clickZ;
					break;
				case 3:
					++clickZ;
					break;
				case 4:
					--clickX;
					break;
				case 5:
					++clickX;
					break;
				}
				
				if (!event.entityPlayer.canPlayerEdit(clickX, clickY, clickZ, event.target.sideHit, event.current)) {
					return;
				}
				
				if (this.placeLiquid(event.world, clickX, clickY, clickZ, event.current) && !event.entityPlayer.capabilities.isCreativeMode) {
					event.result = new ItemStack(net.minecraft.init.Items.bucket);
					event.setResult(Result.ALLOW);
				}
			}
			*/
		}
		else {
			ItemStack filledBucket = fillOreBucket(event.world, event.target);
			
			if (filledBucket == null) {
				return;
			}
			
			event.result = filledBucket;
			event.setResult(Result.ALLOW);
		}
	}

	private boolean placeLiquid(World world, int blockX, int blockY, int blockZ, ItemStack item) {
		if (!world.getBlock(blockX, blockY, blockZ).isAir(world, blockY, blockY, blockZ)
				&& world.getBlock(blockX, blockY, blockZ).getMaterial().isSolid()) {
			return false;
		}
		try {
			Block block = FluidContainerRegistry.getFluidForFilledItem(item).getFluid().getBlock();
			
			if (block == null) {
				return false;
			}
			
			world.setBlock(blockX, blockY, blockZ, block, 0, 3);
		}
		catch (Exception e) {
			OresPlus.log.info("ERROR: caught exception placing liquid block" + e);
			return false;
		}
		return true;
	}

	private ItemStack fillOreBucket(World world, MovingObjectPosition target) {
		Block targetBlock = world.getBlock(target.blockX, target.blockY, target.blockZ);
		if (!(targetBlock instanceof BlockFluidClassic)) {
			return null;
		}
		ItemStack filledBucket = FluidContainerRegistry.fillFluidContainer(new FluidStack(((BlockFluidClassic)targetBlock).getFluid(), 1000), new ItemStack(net.minecraft.init.Items.bucket));
		if (filledBucket != null && world.getBlockMetadata(target.blockX, target.blockY, target.blockZ) == 0) {
			world.setBlockToAir(target.blockX, target.blockY, target.blockZ);
			return filledBucket;
		}
		else {
			return null;
		}
	}
} public class GuiHandler implements IGuiHandler {

	@Override
	public Object getServerGuiElement(int ID, EntityPlayer player, World world,
			int x, int y, int z) {
		switch (ID) {
		case 0:
			TileEntityGrinder teGrinder = (TileEntityGrinder) world.getTileEntity(x, y, z);
			return new ContainerGrinder(player.inventory, teGrinder);
		case 1:
			TileEntityCracker teCracker = (TileEntityCracker)world.getTileEntity(x, y, z);
			return new ContainerCracker(player.inventory, teCracker);
		default:
			return null;
		}
	}
	
	@Override
	public Object getClientGuiElement(int ID, EntityPlayer player, World world,
			int x, int y, int z) {
		switch (ID) {
		case 0:
			TileEntityGrinder teGrinder = (TileEntityGrinder) world.getTileEntity(x, y, z);
			return new GuiGrinder(player.inventory, teGrinder);
		case 1:
			TileEntityCracker teCracker = (TileEntityCracker)world.getTileEntity(x, y, z);
			return new GuiCracker(player.inventory, teCracker);
		default:
			return null;
		}
	}
} public class IMCHandler {
	
	public void recieveIMC(FMLInterModComms.IMCEvent event) {
		OresPlus.log.info("Recieved IMC evemt");
		for (IMCMessage message : event.getMessages()) {
			try {
				if (!message.isNBTMessage())
					break;
				NBTTagCompound messageData = message.getNBTValue();
				if (message.key.equals("registerOre")) {
					if (!messageData.getString("oreName").equals("") && !Ores.manager.isOreRegistered(messageData.getString("oreName"))) {
						Ores.manager.registerOre(messageData.getString("oreName"), GameRegistry.findBlock(message.getSender(), messageData.getString("oreName")));
					}
				}
				else if (message.key.equals("registerGenerator")) {
					if (!messageData.getString("oreName").equals("") && !Ores.manager.isOreRegistered(messageData.getString("oreName"))) {
						OreGenClass oreGen = new OreGenClass(
								messageData.getString("genName"),
								messageData.getString("oreName"), 
								messageData.getBoolean("genEnabled"), 
								messageData.getInteger("genDim"), 
								messageData.getInteger("numVeins"), 
								messageData.getInteger("veinSize"), 
								messageData.getInteger("minY"), 
								messageData.getInteger("maxY"), 
								messageData.getBoolean("doRegen"), 
								OreGenType.NORMAL, 
								messageData.getInteger("oreDensity"),
								messageData.getString("regenKey"));
						new WorldGenOre(oreGen);
					}
				}
			}
			catch (Exception e) {
				OresPlus.log.info("Error, recieved invalid IMC message from " + message.getSender());
				e.printStackTrace();
			}
		}
	}

} public interface IProxy {
	public void registerArmorRenderer(String armorName);
} public class ItemMapHelper {
	private HashMap<String, Item> remapList = new HashMap();

	public ItemMapHelper() {
		// Add remaps for storage blocks (oreBlockXXX -> blockXXX)
		for (MetallicOres ore : MetallicOres.values()) {
			remapList.put("OresPlus:oreBlock" + ore.toString(), ore.block.source.getItem());
			if (!ore.isAlloy) {
				remapList.put("OresPlus:nativeCluster" + ore.toString(), ore.cluster.source.getItem());
			}
		}
		for (GemstoneOres ore : GemstoneOres.values()) {
			remapList.put("OresPlus:oreBlock" + ore.toString(), ore.block.source.getItem());
		}
		for (DustyOres ore : DustyOres.values()) {
			remapList.put("OresPlus:oreBlock" + ore.toString(), ore.block.source.getItem());
		}
		// add Peridot remaps
		remapList.put("OresPlus:oreGreenSapphire", GemstoneOres.Peridot.ore.source.getItem());
		remapList.put("OresPlus:oreNetherGreenSapphire", GemstoneOres.Peridot.netherOre.source.getItem());
		remapList.put("OresPlus:blockGreenSapphire", GemstoneOres.Peridot.block.source.getItem());
		remapList.put("OresPlus:gemGreenSapphire", GemstoneOres.Peridot.gem.source.getItem());
		// add Mithril remaps
		remapList.put("OresPlus:oreMithral", MetallicOres.Mithril.ore.source.getItem());
		remapList.put("OresPlus:oreNetherMithral", MetallicOres.Mithril.netherOre.source.getItem());
		remapList.put("OresPlus:blockMithral", MetallicOres.Mithril.block.source.getItem());
		remapList.put("OresPlus:ingotMithral", MetallicOres.Mithril.ingot.source.getItem());
		remapList.put("OresPlus:nuggetMithral", MetallicOres.Mithril.nugget.source.getItem());
		remapList.put("OresPlus:dustMithral", MetallicOres.Mithril.dust.source.getItem());
		remapList.put("OresPlus:dustTinyMithral", MetallicOres.Mithril.tinyDust.source.getItem());
		remapList.put("OresPlus:crushedMithral", MetallicOres.Mithril.crushedOre.source.getItem());
		remapList.put("OresPlus:crushedPurifiedMithral", MetallicOres.Mithril.purifiedCrushedOre.source.getItem());
		remapList.put("OresPlus:clusterMithral", MetallicOres.Mithril.cluster.source.getItem());
		remapList.put("OresPlus:clumpMithral", MetallicOres.Mithril.clump.source.getItem());
		remapList.put("OresPlus:dustDirtyMithral", MetallicOres.Mithril.dirtyDust.source.getItem());
		remapList.put("OresPlus:shardMithral", MetallicOres.Mithril.shard.source.getItem());
		remapList.put("OresPlus:crystalMithral", MetallicOres.Mithril.crystal.source.getItem());
		remapList.put("OresPlus:bucketMoltenMithral", MetallicOres.Mithril.bucket.source.getItem());
		//remapList.put("OresPlus:block.molten.mithral", MetallicOres.Mithril.moltenFluidBlock.getItem());
		remapList.put("OresPlus:oreSheldonite", MineralOres.Cooperite.ore.source.getItem());
		remapList.put("OresPlus:dustSheldonite", MineralOres.Cooperite.dust.source.getItem());
		remapList.put("OresPlus:dustTungstate", Items.dustTungsten.item.source.getItem());
	}
	
	public void handleMissingMaps(FMLMissingMappingsEvent event) {
		OresPlus.log.info("recieved missing maps event");
		for (MissingMapping map : event.get()) {
			if (this.remapList.containsKey(map.name)) {
				switch (map.type) {
				case BLOCK:
					OresPlus.log.info("Remapping missing mapping for block " + map.name);
					map.remap(Block.getBlockFromItem(remapList.get(map.name)));
					break;
				default:
					OresPlus.log.info("Remapping missing mapping for item " + map.name);
					map.remap(remapList.get(map.name));
				}
			}
		}
	}

} public class OreEventHandler {
	@SubscribeEvent
	public void chunkLoad(ChunkDataEvent.Load event) {
		NBTTagCompound oresPlusRegen = event.getData().getCompoundTag("OresPlus");
		
		if (oresPlusRegen.hasNoTags()) { // regen info not found, checking for old regen key
			oresPlusRegen.setString("ores", event.getData().getString("OresPlus:regenKey"));
		}
		
	    NBTTagCompound oreRegenArray = oresPlusRegen.getCompoundTag("oreRegenArray");
	    int dimId = event.world.provider.dimensionId;
	    ArrayList<WorldGenOre> oreGenArray = WorldGenCore.oreGenerators.get(dimId);
	    if (oreGenArray != null) {
	    	for (WorldGenOre oreGen : oreGenArray) {
	    		String oreRegenKey = oreRegenArray.getString(oreGen.getOreName());
	    		if (oreRegenKey.equals("")) {
	    			oreRegenKey = oresPlusRegen.getString("ores");
	    		}
	    		if (oreGen.doRegen && !oreGen.regenKey.equals(oreRegenKey)) {
	    			ArrayList<ChunkCoordIntPair> chunks = oreGen.regenList.get(Integer.valueOf(dimId));
	    			if (chunks == null)
	    				chunks = new ArrayList();
	    			chunks.add(event.getChunk().getChunkCoordIntPair());
	    			oreGen.regenList.put(dimId, chunks);
	    		}
	    	}
	    }
		
		if (!OresPlus.regenKeyOil.equals("DISABLED") && !oresPlusRegen.getString("oil").equals(OresPlus.regenKeyOil)) {
			int dim = event.world.provider.dimensionId;
			ArrayList chunks = TickHandler.oilRegenList.get(Integer.valueOf(dim));
			if (chunks == null)
				chunks = new ArrayList();
			chunks.add(event.getChunk().getChunkCoordIntPair());
			TickHandler.oilRegenList.put(Integer.valueOf(dim), chunks);
		}
		
		if (!OresPlus.regenKeyRubberTree.equals("DISABLED") && !oresPlusRegen.getString("rubberTree").equals(OresPlus.regenKeyRubberTree)) {
			int dim = event.world.provider.dimensionId;
			ArrayList chunks = TickHandler.rubberTreeRegenList.get(Integer.valueOf(dim));
			if (chunks == null)
				chunks = new ArrayList();
			chunks.add(event.getChunk().getChunkCoordIntPair());
			TickHandler.rubberTreeRegenList.put(Integer.valueOf(dim), chunks);
		}
		
		if (!OresPlus.regenKeyBeehives.equals("DISABLED") && !oresPlusRegen.getString("beehives").equals(OresPlus.regenKeyBeehives)) {
			int dim = event.world.provider.dimensionId;
			ArrayList chunks = TickHandler.beehiveRegenList.get(Integer.valueOf(dim));
			if (chunks == null)
				chunks = new ArrayList();
			chunks.add(event.getChunk().getChunkCoordIntPair());
			TickHandler.beehiveRegenList.put(Integer.valueOf(dim), chunks);
		}
	}

	@SubscribeEvent
	public void chunkSave(ChunkDataEvent.Save event) {
		NBTTagCompound oresPlusRegen = new NBTTagCompound();
		
		int dimId = event.world.provider.dimensionId;
	    NBTTagCompound oreRegenArray = new NBTTagCompound();
	    ArrayList<WorldGenOre> oreGenArray = WorldGenCore.oreGenerators.get(dimId);
	    if (oreGenArray != null) {
	    	for (WorldGenOre oreGen : oreGenArray) {
	    		oreRegenArray.setString(oreGen.getOreName(), oreGen.regenKey);
	    	}
	    }
	    oresPlusRegen.setTag("oreRegenArray", oreRegenArray);
		oresPlusRegen.setString("ores", OresPlus.regenKeyOre);
		oresPlusRegen.setString("oil", OresPlus.regenKeyOil);
		oresPlusRegen.setString("rubberTree", OresPlus.regenKeyRubberTree);
		oresPlusRegen.setString("beehives", OresPlus.regenKeyBeehives);
		event.getData().setTag("OresPlus", oresPlusRegen);
	}
	
	@SubscribeEvent
	public void worldLoad(WorldEvent.Load event) {
		OresPlus.log.info("Loading ore generators for dimension id " + event.world.provider.dimensionId);
		int dim = event.world.provider.dimensionId;
		if (WorldGenCore.oreGenerators.get(dim) != null) {
			OresPlus.log.debug("Skipping load, dimension already loaded");
			return;
		}
		ArrayList<WorldGenOre> oreGenList = new ArrayList();
		IOreGenerator[] sources;
		switch (dim) {
		case -1:
			sources = OreGeneratorsNether.values();
			break;
		case 1:
			sources = OreGeneratorsEnd.values();
			break;
		default:
			sources = OreGenerators.values();
		}
		for (IOreGenerator oreGen : sources) {
			WorldGenOre generator = oreGen.getOreGenerator(dim);
			if (generator != null) {
				OresPlus.log.debug("Adding generator for " + generator.getOreName() + " to dimension id " + dim);
				oreGenList.add(generator);
			}
		}
		if (!oreGenList.isEmpty()) {
			WorldGenCore.oreGenerators.put(dim, oreGenList);
		}
		OresPlus.log.info("Loaded world gen for dimension id " + dim);
	}
	
	@SubscribeEvent
	public void genOre(GenerateMinable event) {
		switch (event.type) {
		//case EMERALD:
		case QUARTZ:
		case IRON:
		case GOLD:
		case LAPIS:
		case REDSTONE:
		case DIAMOND:
		case COAL:
			event.setResult(Result.DENY);
			break;
		default:
			event.setResult(Result.ALLOW);
		}
	}
} public class OreLog {
	public static Logger log;
	
	private static boolean configured = false;
	
	public static void init(){
		log = LogManager.getLogger(References.MOD_ID);
		configured = true;
	}
	
	public static void log(Level level, String message){
		if (!configured){
			init();
		}
		log.log(level, message, new Object[0]);
	}
	
	public static void info(String message) {
		log(Level.INFO, message);
	}
	
	public static void debug(String message) {
		if (OresPlus.debugMode)
			log(Level.DEBUG, message);
	}

} public class References {
	public static final String MOD_ID = "OresPlus";
    public static final String MOD_NAME = "OresPlus";
    public static final String MOD_VERSION = "@VERSION@";
} public class TickHandler {
	public static HashMap<Integer, ArrayList<ChunkCoordIntPair>> oreRegenList = new HashMap();
	public static HashMap<Integer, ArrayList<ChunkCoordIntPair>> oilRegenList = new HashMap();
	public static HashMap<Integer, ArrayList<ChunkCoordIntPair>> rubberTreeRegenList = new HashMap();
	public static HashMap<Integer, ArrayList<ChunkCoordIntPair>> beehiveRegenList = new HashMap();
	
	@SubscribeEvent
	public boolean onWorldTick(TickEvent.WorldTickEvent event) {
		
		int dimId = event.world.provider.dimensionId;
		ArrayList<WorldGenOre> oreGenArray = WorldGenCore.oreGenerators.get(dimId);
		if (oreGenArray != null) {
			for (WorldGenOre oreGen : oreGenArray) {
				ArrayList<ChunkCoordIntPair> chunks = oreGen.regenList.get(dimId);
				if (chunks != null && !chunks.isEmpty()) {
					ChunkCoordIntPair coords = chunks.get(0);
					oreGen.generate(event.world, event.world.rand, coords.chunkXPos * 16, coords.chunkZPos * 16);
					event.world.getChunkFromChunkCoords(coords.chunkXPos, coords.chunkZPos).setChunkModified();
		        	if (OresPlus.logRegenerations) {
		        		OreLog.info("Regenerated " + oreGen.getOreName() + " at chunk " + coords.chunkXPos + "," + coords.chunkZPos);
		        	}
		        	chunks.remove(0);
		        	oreGen.regenList.put(Integer.valueOf(dimId), chunks);
				}
			}
		}
		
		if (Helpers.BuildCraft.isLoaded()) {
			ArrayList chunks = oilRegenList.get(Integer.valueOf(dimId));
			if (chunks != null && !chunks.isEmpty()) {
				ChunkCoordIntPair coords = (ChunkCoordIntPair) chunks.get(0);
				Chunk chunk = event.world.getChunkFromChunkCoords(coords.chunkXPos, coords.chunkZPos);
				Helpers.BuildCraft.generate(event.world, event.world.rand, chunk.xPosition, chunk.zPosition);
		        if (OresPlus.logRegenerations) {
		            OreLog.info("Regenerated oil at chunk " + coords.chunkXPos + "," + coords.chunkZPos);
		          }
				chunks.remove(0);
				oilRegenList.put(Integer.valueOf(dimId), chunks);
			}
		}
		
		if (Helpers.IC2.isLoaded()) {
			ArrayList chunks = rubberTreeRegenList.get(Integer.valueOf(dimId));
			if (chunks != null && !chunks.isEmpty()) {
				ChunkCoordIntPair coords = (ChunkCoordIntPair) chunks.get(0);
				Chunk chunk = event.world.getChunkFromChunkCoords(coords.chunkXPos, coords.chunkZPos);
				Helpers.IC2.generate(event.world, event.world.rand, chunk.xPosition, chunk.zPosition);
		        if (OresPlus.logRegenerations) {
		            OreLog.info("Regenerated rubber trees at chunk " + coords.chunkXPos + "," + coords.chunkZPos);
		          }
				chunks.remove(0);
				rubberTreeRegenList.put(Integer.valueOf(dimId), chunks);
			}
		}
		
		if (Helpers.Forestry.isLoaded()) {
			ArrayList chunks = beehiveRegenList.get(Integer.valueOf(dimId));
			if (chunks != null && !chunks.isEmpty()) {
				ChunkCoordIntPair coords = (ChunkCoordIntPair) chunks.get(0);
				Chunk chunk = event.world.getChunkFromChunkCoords(coords.chunkXPos, coords.chunkZPos);
				Helpers.Forestry.generate(event.world, event.world.rand, chunk.xPosition, chunk.zPosition);
		        if (OresPlus.logRegenerations) {
		            OreLog.info("Regenerated beehives at chunk " + coords.chunkXPos + "," + coords.chunkZPos);
		          }
				chunks.remove(0);
				beehiveRegenList.put(Integer.valueOf(dimId), chunks);
			}
		}
		
		return true;
	}

} public abstract class ConfigCore {
	public static final String CAT_ORES = "ores";
	public static final String CAT_ORE_GEN = "ore_generation";
	public static final String CAT_REGEN = "regeneration";
	private static final String CAT_CONFIG = "configFile";
	
	protected boolean configured = false;
	protected Configuration config;
	
	protected final int configVersion = 1;
	protected int configFileVersion;
	
	protected static File baseConfigDir;
	
	public static void setBaseDir(File modConfigDir) {
		baseConfigDir = new File(modConfigDir, References.MOD_ID + "/");
	}
	
	public void init(String configName, File configFile) {
		OresPlus.log.info("Initializing " + configName + " Configuration");
		
		this.config = new Configuration(configFile);
		
		this.config.load();
		
		this.config.addCustomCategoryComment(CAT_CONFIG, "Config file versioning");

		if (this.config.hasKey(CAT_CONFIG, "configVersion")) {
		    this.configFileVersion = getInt(CAT_CONFIG, "configVersion", configFileVersion, "Configuration File Version - Do not change, modifying this may break your game");
	    }
	    else {
	    	this.configFileVersion = 0;
	    }
	    OresPlus.log.info("Reading from v" + configFileVersion + " Configuration File");
	}
	
	public void save() {
		OresPlus.log.info("Saving Configuration");
		this.saveQuiet();
	}
	
	public void saveQuiet() {
		if (!configured) {
			OresPlus.log.info("Error - configuration not initialized!");
			return;		
		}
		
		if (configFileVersion != configVersion) {
			Property prop = config.get(CAT_CONFIG, "configVersion", configVersion);
			prop.comment = "Configuration File Version - Do not change, modifying this may break your game";
			prop.set(configVersion);
		}
		
		if (config.hasChanged())
			config.save();
	}
	
	private int getInt(String key, int defaultValue, String comment) {
		return getInt(Configuration.CATEGORY_GENERAL, key, defaultValue, comment);
	}

	private int getInt(String category, String key, int defaultValue, String comment) {
		Property prop = config.get(category, key, defaultValue);
		if (comment != "")
			prop.comment = comment;
		return prop.getInt(defaultValue);
	}

	public boolean getBoolean(String key, boolean defaultValue, String comment) {
		Property prop = config.get(Configuration.CATEGORY_GENERAL, key, defaultValue);
		if (comment != "")
			prop.comment = comment;
		return prop.getBoolean(defaultValue);
	}
	
	public boolean getBoolean(String key, boolean defaultValue) {
		return getBoolean(key, defaultValue, "");
	}
	
	public String getString(String catagory, String key, String defaultValue, String comment) {
		Property prop = config.get(catagory, key, defaultValue);
		if (comment != "")
			prop.comment = comment;
		return prop.getString();
	}
	
	public String getString(String key, String defaultValue, String comment) {
		return getString(Configuration.CATEGORY_GENERAL, key, defaultValue, comment);
	}

	public String getString(String key, String defaultValue) {
		return getString(Configuration.CATEGORY_GENERAL, key, defaultValue, "");
	}
	
	private String getOreGenCfgLine(OreGenClass oreConfig) {
		if (oreConfig == null)
			return null;
		return Boolean.toString(oreConfig.enabled) + ","
				+ oreConfig.density + ","
				+ Boolean.toString(oreConfig.doRegen) + ","
				+ oreConfig.regenKey;
	}
	
	public OreGenClass getOreGen(OreGenClass oreConfig) {
		if (oreConfig != null) {
			Property prop = config.get(CAT_ORE_GEN, oreConfig.name, getOreGenCfgLine(oreConfig));
			String cfg[] = prop.getString().split(",");
			boolean configChanged = false;
			switch (configFileVersion) {
			case 1:
				oreConfig.enabled = Boolean.parseBoolean(cfg[0]);
				oreConfig.density = Integer.parseInt(cfg[1]);
				oreConfig.doRegen = Boolean.parseBoolean(cfg[2]);
				oreConfig.regenKey = cfg[3];
				break;
			default:
				switch (cfg.length) {
				case 3: // v0.1.4 - 0.4.23
					oreConfig.enabled = Boolean.parseBoolean(cfg[0]);
					oreConfig.density = Integer.parseInt(cfg[1]);
					oreConfig.doRegen = Boolean.parseBoolean(cfg[2]);
					break;
				case 4: // current
					oreConfig.enabled = Boolean.parseBoolean(cfg[0]);
					oreConfig.density = Integer.parseInt(cfg[1]);
					oreConfig.doRegen = Boolean.parseBoolean(cfg[2]);
					oreConfig.regenKey = cfg[3];
					break;
				case 8: // v0.1.1 - v0.1.3
					oreConfig.enabled = Boolean.parseBoolean(cfg[1]);
					oreConfig.doRegen = Boolean.parseBoolean(cfg[7]);
					configChanged = true;
					break;
				default:
					OresPlus.log.info("Could not read config for ore " + oreConfig.name + ". Resetting to default");
					configChanged = true;
				}
			}
			if (configChanged)
				prop.set(getOreGenCfgLine(oreConfig));
		}
		return oreConfig;
	}
	
	private String getOreCfgLine(OreClass ore) {
		if (ore == null)
			return null;
		return Boolean.toString(ore.enabled) + ","
				+ ore.source.name();
	}
	
	public OreClass getOre(OreClass ore) {
		if (ore != null) {
			Property prop = config.get(CAT_ORES, ore.name, getOreCfgLine(ore));
			String cfg[] = prop.getString().split(",");
			
			boolean configChanged = false;
			switch (cfg.length) {
			case 2:
				ore.enabled = Boolean.parseBoolean(cfg[0]);
				ore.source = OreSources.valueOf(cfg[1]);
				break;
			case 3: // v0.1.1 - v0.1.3
				ore.enabled = Boolean.parseBoolean(cfg[0]);
				configChanged = true;
				break;
			default:
				OresPlus.log.info("Could not read config for ore " + ore.name + ". Resetting to default");
				configChanged = true;
			}
			if (configChanged)
				prop.set(getOreCfgLine(ore));
		}
		return ore;
	}

} public class ConfigMain extends ConfigCore {
	public boolean enableMachines = true;

	public void init(FMLPreInitializationEvent event) {
		
		File configFile = new File(baseConfigDir, References.MOD_ID + ".cfg");
		if (!configFile.exists()) {
			File oldConfigFile = event.getSuggestedConfigurationFile();
			if (oldConfigFile.exists())
				oldConfigFile.renameTo(configFile);
		}
		
		super.init("Main", configFile);
		
	    config.addCustomCategoryComment(CAT_REGEN, "Configure general regeneration options here");
		
		configured = true;
	}
	
	public void load() {
		this.enableMachines = this.getBoolean("enableMachines", this.enableMachines, "Set to false to disable crafting of this mods machinary");
	}

} public class AppEngHelper extends OresHelper {
	private static IAppEngApi api = null;
	
	public AppEngHelper() {
		super("appliedenergistics2");
	}
	
	@Override
	public void preInit() {
		if (!this.isLoaded()) {
			OresPlus.log.info("Applied Energistics 2 not found, integration helper disabled");
			return;
		}
	    try 
	    {
	        api = AEApi.instance();
	    }
	    catch (Exception e) {
	        OresPlus.log.info("Error initializing Applied Energistics 2");
	        return;
	    }
	    OresPlus.log.info("Applied Energistics 2 found, integration helper Initialized");
	}


	@Override
	public void init() {
		if (!this.isLoaded()) 
			return;
	}

	@Override
	public void postInit() {
		if (!this.isLoaded()) 
			return;
	}
	
	@Override
	public void generate(World world, Random rand, int chunkX, int chunkZ) { }

	@Override
	public void registerRecipe(RecipeType recipeType, ItemStack input,
			NBTTagCompound metadata, ItemStack... outputs) {
		if (!this.isLoaded())
			return;
		
		switch (recipeType) {
		case Grinder:
	        try {
	        	api.registries().grinder().addRecipe(input, outputs[0], metadata.getInteger("cranks"));
	        }
	        catch (Exception e) {
	        	OresPlus.log.info("Error registering AppEng2 grinder recipe");
	        }
	        break;
		default:
			break;
		}
	}

	@Override
	public void registerGasRecipe(RecipeType recipeType, Object input,
			NBTTagCompound metadata, Object output, Object secondaryOutput) { }

} public class BCHelper extends OresHelper {
	private Class genOilClass;
	private Object genOilClassObj;
	private Method genOilMethod;
	private String[] subMods = { "BuildCraft|Builders", "BuildCraft|Energy", "BuildCraft|Factory", "BuildCraft|Silicon", "BuildCraft|Transport" };
	
	public BCHelper() {
		super("BuildCraft|Core");
	}
	
	public void preInit() {
		if (!this.isLoaded()) {
			OresPlus.log.info("BuildCraft not found, integration helper disabled");
			return;
		}
		
		if (this.isEnergyLoaded()) {
			try {
				this.genOilClass = Class.forName("buildcraft.energy.worldgen.OilPopulate");
			} catch (ClassNotFoundException e) {
				OresPlus.log.info("Could not find OilPopulate class");
				e.printStackTrace();
			}
			
			Constructor c = null;
			try {
				c = this.genOilClass.getDeclaredConstructor();
			} catch (NoSuchMethodException e) {
				OresPlus.log.info("Could not find constructor");
				e.printStackTrace();
			} catch (SecurityException e) {
				OresPlus.log.info("Access denied to contructor");
				e.printStackTrace();
			}
			if (c != null) {
				c.setAccessible(true);
				try {
					this.genOilClassObj = c.newInstance();
				} catch (InstantiationException e) {
					OresPlus.log.info("InstatianException");
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					OresPlus.log.info("Illegal Access");
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					OresPlus.log.info("Illrgal args");
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					OresPlus.log.info("Target exception");
					e.printStackTrace();
				}
			}
			
			if (this.genOilClass != null && this.genOilClassObj != null)
				for (Method method : this.genOilClass.getMethods()) {
					if (method.getName().equals("generateOil")) 
						this.genOilMethod = method;
				
				}
		}	
		OresPlus.log.info("BuildCraft found, integration helper initialized");
	}
	
	@Override
	public void init() {
		if (!this.isLoaded()) 
			return;
	}

	@Override
	public void postInit() {
		if (!this.isLoaded()) 
			return;
	}
	
	private boolean isEnergyLoaded() {
		return Loader.isModLoaded("BuildCraft|Energy");
	}
	
	public void generate(World world, Random rand, int chunkX, int chunkZ) {
		if (!this.isEnergyLoaded() || this.genOilMethod == null)
			return;
		
		try {
			this.genOilMethod.invoke(this.genOilClassObj, world, rand, chunkX, chunkZ);
		} catch (IllegalAccessException e) {
			OresPlus.log.info("Call to OilPopulate.generate was denied");
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			OresPlus.log.info("Call to OilPopulate.generate was failed, illegal arguments");
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			OresPlus.log.info("OilPopulate.generate caused an exception");
			e.printStackTrace();
		}
		
	}

	@Override
	public void registerRecipe(RecipeType recipeType, ItemStack input,
			NBTTagCompound metadata, ItemStack... outputs) { }
	
	@Override
	public Block getBlock(String blockName) {
		Block result = super.getBlock(blockName);
		if (result == null) {
			for (String subModName : subMods ) {
				Block subModResult = GameRegistry.findBlock(subModName, blockName);
				if (subModResult != null) {
					result = subModResult;
				}
			}
		}
		return result;
	}

	@Override
	public void registerGasRecipe(RecipeType recipeType, Object input,
			NBTTagCompound metadata, Object output, Object secondaryOutput) { }

} public enum Helpers {
	AppliedEnergistics(new AppEngHelper()),
	BuildCraft(new BCHelper()),
	Forestry(new ForestryHelper()),
	IC2(new IC2Helper()),
	Mekanism(new MekanismHelper()),
	RailCraft(new RCHelper()),
	ThaumCraft(new TCHelper()),
	ThermalExpansion(new TEHelper()),
	Tinkers(new TinkersHelper()),
	Treecapitator(new TreecapitatorHelper()), 
	BigReactors(new BigReactorsHelper()), 
	MineFactoryReloaded(new MFRHelper());
	
	private OresHelper _oresHelper;
	
	private Helpers(OresHelper oresHelper) {
		_oresHelper = oresHelper;
	}
	
	public void preInit() {
		this._oresHelper.preInit();
	}
	
	public void init() {
		this._oresHelper.init();
	}
	
	public void postInit() {
		this._oresHelper.postInit();
	}
	
	public boolean isLoaded() {
		return this._oresHelper.isLoaded();
	}
	
	public void generate(World world, Random rand, int chunkX, int chunkZ) {
		this._oresHelper.generate(world, rand, chunkX, chunkZ);
	}
	
	public Block getBlock(String blockName) {
		return this._oresHelper.getBlock(blockName);
	}
	
	public Item getItem(String itemName) {
		return this._oresHelper.getItem(itemName);
	}
	
	public void registerRecipe(RecipeType recipeType, ItemStack input, ItemStack... outputs) {
		this.registerRecipe(recipeType, input, null, outputs);
	}
	
	public void registerRecipe(RecipeType recipeType, ItemStack input, NBTTagCompound metadata, ItemStack... outputs) {
		this._oresHelper.registerRecipe(recipeType, input, metadata, outputs);
	}

	public void registerGasRecipe(RecipeType recipeType,
			Object input, NBTTagCompound metadata, Object output) {
		this.registerGasRecipe(recipeType, input, metadata, output, null);
	}
	
	public void registerGasRecipe(RecipeType recipeType,
			Object input, NBTTagCompound metadata, Object output, Object secondaryOutput) {
		// TODO Auto-generated method stub
		this._oresHelper.registerGasRecipe(recipeType, input, metadata, output, secondaryOutput);
	}
	
} public class FluidManager {
	public static void init() {
		Ores.fluidManager = new OreFluidManager();
		
		for (Fluids fluid : Fluids.values()) {
			fluid.registerFluid();
		}
		
		for (MetallicOres ore : MetallicOres.values()) {
			ore.registerFluids();
		}
	}
} public class GasManager {
	public static void init() {
		for (Gases gas : Gases.values()) {
			gas.registerGas();
		}
		
		for (MetallicOres ore : MetallicOres.values()) {
			ore.registerGases();
		}
		
		for (MineralOres ore : MineralOres.values()) {
			ore.registerGases();
		}
	}
} public class ItemCore extends Item{
	protected int itemId;
	
	public ItemCore(String itemName) {
		super();
		setUnlocalizedName(itemName);
		setTextureName(References.MOD_ID + ":" + itemName);
		Ores.manager.registerOreItem(itemName, this);
		GameRegistry.registerItem(this, itemName);
		OreDictionary.registerOre(itemName, this);
	}

	public ItemCore addOreDictionaryName(String name) {
		OreDictionary.registerOre(name, this);
		return this;
	}    
} public class ItemManager {
	private static boolean isInitialized = false;
	
	public static ItemArmor.ArmorMaterial armorAdamantine = EnumHelper.addArmorMaterial("ADAMANTINE", 35, new int[] { 3, 8, 6, 3 }, 8);
	public static ItemArmor.ArmorMaterial armorColdiron = EnumHelper.addArmorMaterial("COLDIRON", 15, new int[] { 2, 6, 5, 2 }, 18);
	public static ItemArmor.ArmorMaterial armorMithral = EnumHelper.addArmorMaterial("MITHRAL", 20, new int[] { 3, 8, 6, 3 }, 25);

	public static Item.ToolMaterial toolAdamantine = EnumHelper.addToolMaterial("ADAMANTINE", 3, 1250, 12.0F, 3.0F, 16);
	public static Item.ToolMaterial toolColdiron = EnumHelper.addToolMaterial("COLDIRON", 2, 250, 6.0F, 2.0F, 17);
	public static Item.ToolMaterial toolMithral = EnumHelper.addToolMaterial("MITHRAL", 2, 560, 8.0F, 3.0F, 20);
	
	public static OreItemStack armorAdamantineHelmet;
	public static OreItemStack armorAdamantineChestplate;
	public static OreItemStack armorAdamantineLeggings;
	public static OreItemStack armorAdamantineBoots;
	public static OreItemStack armorColdironHelmet;
	public static OreItemStack armorColdironChestplate;
	public static OreItemStack armorColdironLeggings;
	public static OreItemStack armorColdironBoots;
	public static OreItemStack armorMithralHelmet;
	public static OreItemStack armorMithralChestplate;
	public static OreItemStack armorMithralLeggings;
	public static OreItemStack armorMithralBoots;
	public static OreItemStack toolAdamantineAxe;
	public static OreItemStack toolAdamantineHoe;
	public static OreItemStack toolAdamantinePickaxe;
	public static OreItemStack toolAdamantineSpade;
	public static OreItemStack toolAdamantineSword;
	public static OreItemStack toolColdironAxe;
	public static OreItemStack toolColdironHoe;
	public static OreItemStack toolColdironPickaxe;
	public static OreItemStack toolColdironSpade;
	public static OreItemStack toolColdironSword;
	public static OreItemStack toolMithralAxe;
	public static OreItemStack toolMithralHoe;
	public static OreItemStack toolMithralPickaxe;
	public static OreItemStack toolMithralSpade;
	public static OreItemStack toolMithralSword;

	public static void init() {
		if (isInitialized)
		{
			OresPlus.log.info("Item initialization failed, already initialized");
		}
		else
		{
			OresPlus.log.info("Initializing Items");
			
			for (MetallicOres ore : MetallicOres.values()) {
				ore.registerItems();
			}
			
			for (GemstoneOres ore : GemstoneOres.values()) {
				ore.registerItems();
			}
			
			for (DustyOres ore : DustyOres.values()) {
				ore.registerItems();
			}
			
			for (MineralOres ore : MineralOres.values()) {
				ore.registerItems();
			}
			
			for (Items item : Items.values()) {
				item.registerItems();;
			}
			
		    armorAdamantineHelmet = new OreItemStack(new OreArmor("armorAdamantineHelmet", armorAdamantine, 2, 0));
		    armorAdamantineChestplate = new OreItemStack(new OreArmor("armorAdamantineChestplate", armorAdamantine, 2, 1));
		    armorAdamantineLeggings = new OreItemStack(new OreArmor("armorAdamantineLeggings", armorAdamantine, 2, 2));
		    armorAdamantineBoots = new OreItemStack(new OreArmor("armorAdamantineBoots", armorAdamantine, 2, 3));
		    armorColdironHelmet = new OreItemStack(new OreArmor("armorColdironHelmet", armorColdiron, 2, 0));
		    armorColdironChestplate = new OreItemStack(new OreArmor("armorColdironChestplate", armorColdiron, 2, 1));
		    armorColdironLeggings = new OreItemStack(new OreArmor("armorColdironLeggings", armorColdiron, 2, 2));
		    armorColdironBoots = new OreItemStack(new OreArmor("armorColdironBoots", armorColdiron, 2, 3));
		    armorMithralHelmet = new OreItemStack(new OreArmor("armorMithralHelmet", armorMithral, 2, 0));
		    armorMithralChestplate = new OreItemStack(new OreArmor("armorMithralChestplate", armorMithral, 2, 1));
		    armorMithralLeggings = new OreItemStack(new OreArmor("armorMithralLeggings", armorMithral, 2, 2));
		    armorMithralBoots = new OreItemStack(new OreArmor("armorMithralBoots", armorMithral, 2, 3));
		    toolAdamantineAxe = new OreItemStack(new OreAxe("toolAdamantineAxe", toolAdamantine));
		    toolAdamantineHoe = new OreItemStack(new OreHoe("toolAdamantineHoe", toolAdamantine));
		    toolAdamantinePickaxe = new OreItemStack(new OrePickaxe("toolAdamantinePickaxe", toolAdamantine));
		    toolAdamantineSpade = new OreItemStack(new OreSpade("toolAdamantineSpade", toolAdamantine));
		    toolAdamantineSword = new OreItemStack(new OreSword("toolAdamantineSword", toolAdamantine));
		    toolColdironAxe = new OreItemStack(new OreAxe("toolColdironAxe", toolColdiron));
		    toolColdironHoe = new OreItemStack(new OreHoe("toolColdironHoe", toolColdiron));
		    toolColdironPickaxe = new OreItemStack(new OrePickaxe("toolColdironPickaxe", toolColdiron));
		    toolColdironSpade = new OreItemStack(new OreSpade("toolColdironSpade", toolColdiron));
		    toolColdironSword = new OreItemStack(new OreSword("toolColdironSword", toolColdiron));
		    toolMithralAxe = new OreItemStack(new OreAxe("toolMithralAxe", toolMithral));
		    toolMithralHoe = new OreItemStack(new OreHoe("toolMithralHoe", toolMithral));
		    toolMithralPickaxe = new OreItemStack(new OrePickaxe("toolMithralPickaxe", toolMithral));
		    toolMithralSpade = new OreItemStack(new OreSpade("toolMithralSpade", toolMithral));
		    toolMithralSword = new OreItemStack(new OreSword("toolMithralSword", toolMithral));

			isInitialized = true;
		}
	}

	public static void registerAspects() {
		if (Helpers.ThaumCraft.isLoaded()) {
			ThaumcraftApi.registerObjectTag(armorAdamantineHelmet.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorAdamantineChestplate.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorAdamantineLeggings.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorAdamantineBoots.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorColdironHelmet.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorColdironChestplate.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorColdironLeggings.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorColdironBoots.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorMithralHelmet.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorMithralChestplate.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorMithralLeggings.source, new AspectList());
			ThaumcraftApi.registerObjectTag(armorMithralBoots.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolAdamantineAxe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolAdamantineHoe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolAdamantinePickaxe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolAdamantineSpade.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolAdamantineSword.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolColdironAxe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolColdironHoe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolColdironPickaxe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolColdironSpade.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolColdironSword.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolMithralAxe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolMithralHoe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolMithralPickaxe.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolMithralSpade.source, new AspectList());
			ThaumcraftApi.registerObjectTag(toolMithralSword.source, new AspectList());
		}
	}
} public enum Items {
	clumpAntimony,
	clumpTitanium,
	crushedUranium,
	crystalAntimony,
	crystalTitanium,
	dustAntimony,
	dustCharcoal (108.6D), 
	dustCoal (108.6D), 
	dustDirtyAntimony,
	dustDirtyTitanium,
	dustMagnesium,
	dustSodalite,
	dustTinyTitanium,
	dustTinyTungsten,
	dustTitanium,
	dustTungsten,
	gemIridium (12000.0),
	gemOlivine,
	gemRedGarnet,
	gemYellowGarnet,
	machineCasing,
	shardAntimony,
	shardTitanium,
	itemBitumen,
	itemMercury; 
	
	public OreItemStack item;
	private AspectList _aspects;
	private double _uuCost;
	
	private Items(AspectList aspects, double uuCost) {
		this._aspects = aspects;
		this._uuCost = uuCost;
	}
	
	private Items() {
		this(new AspectList(), 0.0D);
	}
	
	private Items(double uuCost) {
		this(new AspectList(), uuCost);
	}
	
	public void registerItems() {
		item = new OreItemStack(new ItemCore(this.toString()).setCreativeTab(CreativeTabs.tabMaterials));
	}

	public void registerAspects() {
		if (Helpers.ThaumCraft.isLoaded() && this._aspects.size() > 0)
			ThaumcraftApi.registerObjectTag(this.item.source, this._aspects);
	}
	
	public void registerRecipes() {
		if (this._uuCost != 0.0D) {
			RecipeManager.addUUMatterRecipe(this.item.source, this._uuCost);
		}
	}
} public class NetHandler {
	public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(References.MOD_ID.toLowerCase());
	
	public static void init() {
		INSTANCE.registerMessage(PacketGrinder.class, PacketGrinder.class, 0, Side.CLIENT);
		INSTANCE.registerMessage(PacketCracker.class, PacketCracker.class, 1, Side.CLIENT);
	}
} public enum MetallicOres implements IOreList {
	Adamantine(3, Aspect.ARMOR, 3500.0D),
	Aluminium(2, Aspect.EXCHANGE, 650.0D),
	Ardite(4, Aspect.VOID, 2200.0D),
	Brass(Aspect.MECHANISM, true),
	Bronze(Aspect.MECHANISM, true),
	Cobalt(4, Aspect.CRAFT, 1500.0D),
	Coldiron(2, Aspect.COLD, 2000.0D),
	Copper(1, Aspect.EXCHANGE, 165.32555827439467D),
	Electrum(Aspect.EXCHANGE, true),
	Gold(2, Aspect.GREED, 0.0D), // 1888.8470535343595
	Iron(1, Aspect.METAL, 0.0D), // 200.16909378760914
	Lead(1, Aspect.ORDER, 1673.377568334827D),
	Manganese(2, Aspect.ORDER, 800.0D),
	Mithril(3, Aspect.MAGIC, 3200.0D),
	Nickel(2, Aspect.ORDER, 1200.0D),
	Osmium(1, Aspect.ARMOR, 1000.D),
	Platinum(2, Aspect.GREED, 2500.0D),
	Silver(2, Aspect.GREED, 1750.0D),
	Tin(1, Aspect.CRYSTAL, 199.90120532935603D),
	Yellorium(2, Aspect.ENERGY, 2608.8982568638758D),
	Zinc(2, Aspect.CRYSTAL, 1100.0D);
	
	public static ArrayList<MetallicOres> mekanismOres = new ArrayList();

	public String oreName;
	public String netherOreName;
	public String blockName;
	public String ingotName;
	public String nuggetName;
	public String dustName;
	public String tinyDustName;
	public String crushedOreName;
	public String purifiedCrushedOreName;
	public String clusterName;
	public String clumpName;
	public String dirtyDustName;
	public String shardName;
	public String slurryName;
	public String cleanSlurryName;
	public String crystalName;
	public String moltenFluidName;
	public String moltenFluidBlockName;
	public String bucketName;
	
	public OreItemStack ore;
	public OreItemStack netherOre;
	public OreItemStack block;
	public OreItemStack ingot;
	public OreItemStack nugget;
	public OreItemStack dust;
	public OreItemStack tinyDust;
	public OreItemStack crushedOre;
	public OreItemStack purifiedCrushedOre;
	public OreItemStack cluster;
	public OreItemStack clump;
	public OreItemStack dirtyDust;
	public OreItemStack shard;
	public OreItemStack crystal;
	public OreItemStack bucket;
	
	public OreGas slurry;
	public OreGas cleanSlurry;
	
	public Fluid moltenFluid;
	public Block moltenFluidBlock;
	
	public boolean isAlloy;

	private int _harvestLevel;
	private int _xpLow;
	private int _xpHigh;
	private OreDrops _drops;
	private OreSources _source;
	private float _smeltXP;
	private Aspect _secondaryAspect;
	private int _tradeToAmount;
	private int _tradeFromAmount;
	private double _uuCost;
	
	public boolean enabled;
	
	private MetallicOres(Aspect secondaryAspect, boolean isAlloy) {
		this(0, secondaryAspect, isAlloy, 0.0D);
	}
	
	private MetallicOres(int harvestLevel, Aspect secondaryAspect, double uuCost) {
		this(harvestLevel, secondaryAspect, false, uuCost);
	}
		
	private MetallicOres(int harvestLevel, Aspect secondaryAspect, boolean isAlloy, double uuCost) {
		this(harvestLevel, secondaryAspect, isAlloy, 0, 0, uuCost);
	}
	
	private MetallicOres(int harvestLevel, Aspect secondaryAspect, boolean isAlloy, int tradeToAmount, int tradeFromAmount, double uuCost) {
		this.oreName = "ore" + this.toString();
		this.netherOreName = "oreNether" + this.toString();
		this.blockName = "block" + this.toString();

		this.ingotName = "ingot" + this.toString();
		this.nuggetName = "nugget" + this.toString();
		this.dustName = "dust" + this.toString();
		this.tinyDustName = "dustTiny" + this.toString(); 
		this.crushedOreName = "crushed" + this.toString();
		this.purifiedCrushedOreName = "crushedPurified" + this.toString(); 
		this.clusterName = "cluster" + this.toString();
		this.clumpName = "clump" + this.toString();
		this.dirtyDustName = "dustDirty" + this.toString();
		this.shardName = "shard" + this.toString();
		this.crystalName = "crystal" + this.toString();
		this.slurryName = "slurry" + this.toString();
		this.cleanSlurryName = "slurryClean" + this.toString();
		this.moltenFluidName = this.toString().toLowerCase() + ".molten";
		this.moltenFluidBlockName = "fluid.molten." + this.toString().toLowerCase();
		this.bucketName = "bucketMolten" + this.toString();
		
		this.enabled = true;

		this._harvestLevel = harvestLevel;
		this._xpLow = 0;
		this._xpHigh = 0;
		this._source = OreSources.DEFAULT;
		this.isAlloy = isAlloy;
		this._drops = OreDrops.ORE;
		this._secondaryAspect = secondaryAspect;
		this._uuCost = uuCost;
	}

	@Override
	public OreClass getDefaultConfig() {
		return new OreClass(this.oreName, this.enabled, this._harvestLevel, 
				this._xpLow, this._xpHigh, this._drops, this._source);
	}

	@Override
	public OreClass getDefaultConfigNether() {
		return new OreClass(this.netherOreName, this.enabled, this._harvestLevel, 
				this._xpLow, this._xpHigh, this._drops, this._source);
	}
	
	private boolean isVanilla() {
		return (this == Iron || this == Gold);
	}

	@Override
	public void registerBlocks() {
		// Register Ore
		if (!this.isVanilla() && !this.isAlloy) {
			this.ore = new OreItemStack(new BlockOre(this.getDefaultConfig()));
		}
		else if (this == Gold) {
			this.ore = new OreItemStack(net.minecraft.init.Blocks.gold_ore);
		}
		else if (this == Iron) {
			this.ore = new OreItemStack(net.minecraft.init.Blocks.iron_ore);
		}
		
		// Register Nether Ore
		if (!this.isAlloy)	{
			this.netherOre = new OreItemStack(new BlockOre(this.getDefaultConfigNether(), true));
		}
		
		// Register Storage Block
		if (!this.isVanilla()) {
			this.block = new OreItemStack(new BlockCore(Material.iron, this.blockName)
				.setCreativeTab(CreativeTabs.tabBlock)
				.setHardness(5.0F)
				.setResistance(10.0F)
				.setStepSound(Block.soundTypeMetal));
			OreDictionary.registerOre(this.blockName, this.block.source);
		}
		else if (this == Gold) {
			this.block = new OreItemStack(net.minecraft.init.Blocks.gold_block);
		}
		else if (this == Iron) {
			this.block = new OreItemStack(net.minecraft.init.Blocks.iron_block);
		}
	}

	@Override
	public void registerItems() {
		// Register Ingot
		if (!this.isVanilla()) {
			this.ingot = new OreItemStack(new ItemCore(this.ingotName).setCreativeTab(CreativeTabs.tabMaterials));
		}
		else if (this == Gold) {
			this.ingot = new OreItemStack(net.minecraft.init.Items.gold_ingot);
		}
		else if (this == Iron) {
			this.ingot = new OreItemStack(net.minecraft.init.Items.iron_ingot);
		}
		
		// Register Nugget
		if (this != Gold) {
			this.nugget = new OreItemStack(new ItemCore(this.nuggetName).setCreativeTab(CreativeTabs.tabMaterials));
		}
		else {
			this.nugget = new OreItemStack(net.minecraft.init.Items.gold_nugget);
		}
		
		// Register Dust & Tiny Dust
		this.dust = new OreItemStack(new ItemCore(this.dustName).setCreativeTab(CreativeTabs.tabMaterials));
		this.tinyDust = new OreItemStack(new ItemCore(this.tinyDustName).setCreativeTab(CreativeTabs.tabMaterials));

		// Register Crushed & Purified Crushed Ores
		if (!this.isAlloy) {
			this.crushedOre = new OreItemStack(new ItemCore(this.crushedOreName).setCreativeTab(CreativeTabs.tabMaterials));
			this.purifiedCrushedOre = new OreItemStack(new ItemCore(this.purifiedCrushedOreName).setCreativeTab(CreativeTabs.tabMaterials));
		}
		
		// register native clusters
		if (!this.isAlloy) {
			this.cluster = new OreItemStack(new ItemCore(this.clusterName).setCreativeTab(CreativeTabs.tabMaterials));
		}
		
		// register clumps & dirty dusts
		if (!this.isAlloy) {
			this.clump = new OreItemStack(new ItemCore(this.clumpName).setCreativeTab(CreativeTabs.tabMaterials));
			this.dirtyDust = new OreItemStack(new ItemCore(this.dirtyDustName).setCreativeTab(CreativeTabs.tabMaterials));
			this.shard = new OreItemStack(new ItemCore(this.shardName).setCreativeTab(CreativeTabs.tabMaterials));
			this.crystal = new OreItemStack(new ItemCore(this.crystalName).setCreativeTab(CreativeTabs.tabMaterials));
		}
		
		// register bucket of molten ore
		this.bucket = new OreItemStack(new OreBucket(this.bucketName, this.moltenFluidBlock).setCreativeTab(CreativeTabs.tabMisc));
	}

	@Override
	public void registerRecipes() {
		OreItemStack stoneDust = new OreItemStack(new ItemStack(Helpers.IC2.getItem("itemDust"), 1, 9));

		if (!this.isVanilla()) {
			// add ingot -> oreBlock recipe
			RecipeManager.addShapedRecipe(this.block.newStack(), "iii", "iii", "iii", 'i', ingotName);
			
			// add oreBlock -> ingot recipe
			RecipeManager.addShapelessRecipe(this.ingot.newStack(9), this.block.newStack());
			
			// add ore smelting recipe
			if (!this.isAlloy) {
				RecipeManager.addSmelting(this.ore.newStack(), this.ingot.newStack(), this._smeltXP);
			}
		}
		
		if (!this.toString().equals("Gold")) {
			// add ingot -> nugget recipe
			if (this.toString().equals("Iron")) {
				RecipeManager.addShapelessRecipe(this.nugget.newStack(9), this.ingot.newStack());
			}
			else {
				RecipeManager.addShapelessRecipe(this.nugget.newStack(9), ingotName);
			}
			
			// add nugget -> ingot recipe
			RecipeManager.addShapedRecipe(this.ingot.newStack(), "nnn", "nnn", "nnn", 'n', this.nuggetName);
		}
		
		// add ingot Grinder recipes
		RecipeManager.addGrinderRecipe(this.ingot.newStack(), this.dust.newStack());
		
		// add ingot pulverizer (TE) recipes
		if (Helpers.ThermalExpansion.isLoaded()) {
			NBTTagCompound metadata = new NBTTagCompound();
			metadata.setInteger("energy", 2400);
			Helpers.ThermalExpansion.registerRecipe(RecipeType.Grinder, this.ingot.newStack(), metadata, this.dust.newStack());
		}
		
		if (!this.isAlloy) {
			// add nether ore -> ore smelting recipe
			RecipeManager.addSmelting(this.netherOre.newStack(), this.ore.newStack(2), 0.0F);
			
			// add crushed ore smelting recipe
			RecipeManager.addSmelting(this.crushedOre.newStack(), this.ingot.newStack(), this._smeltXP);
			
			// add purified crushed ore smelting recipe
			RecipeManager.addSmelting(this.purifiedCrushedOre.newStack(), this.ingot.newStack(), this._smeltXP);
			
			// add ore grinder recipe
			RecipeManager.addGrinderRecipe(this.ore.newStack(), this.crushedOre.newStack(2));
			
			// Register Thermal Expansion Pulverizer recipe
			if (Helpers.ThermalExpansion.isLoaded()) {
				NBTTagCompound metadata = new NBTTagCompound();
				metadata.setInteger("energy", 4000);
				Helpers.ThermalExpansion.registerRecipe(RecipeType.Grinder, this.ore.newStack(), metadata, this.crushedOre.newStack(2));
			}
			
			if (Helpers.Mekanism.isLoaded() && !mekanismOres.contains(this)) {
				// register slurrys
				this.cleanSlurry = (OreGas)GasRegistry.register(new OreGas(this.cleanSlurryName, this.cleanSlurryName).setVisible(false));
				this.slurry = (OreGas)GasRegistry.register(new OreGas(this.slurryName, this.slurryName).setCleanGas(this.cleanSlurry).setVisible(false));
				
				NBTTagCompound metadata = new NBTTagCompound();
				metadata.setString("gas", "hydrogenChloride");
				
				for (ItemStack dictionaryOre : OreDictionary.getOres(this.oreName)) {
					OreItemStack oreStack = new OreItemStack(dictionaryOre);
					
					// register Mekanism ore->dust enrichment chamber recipe
					Helpers.Mekanism.registerRecipe(RecipeType.EnrichmentChamber, oreStack.newStack(), this.dust.newStack(2));
					
					// register Mekanism ore->clump purification chamber recipe
					Helpers.Mekanism.registerRecipe(RecipeType.PurificationChamber, oreStack.newStack(), this.clump.newStack(3));
					
					// register Mekanism ore->shard chemical injector recipe
					Helpers.Mekanism.registerRecipe(RecipeType.ChemicalInjector, oreStack.newStack(), metadata, this.shard.newStack(4));
					
					// register Mekanism chemical dissolution chamber recipe
					Helpers.Mekanism.registerGasRecipe(RecipeType.ChemicalDissolver, oreStack.newStack(), null, new GasStack(this.slurry, 1000));
					
				}
				
				// register Mekanism dirty dust to dust
				Helpers.Mekanism.registerRecipe(RecipeType.EnrichmentChamber, this.dirtyDust.newStack(), this.dust.newStack());
				
				// register Mekanism shard to clump recipe
				Helpers.Mekanism.registerRecipe(RecipeType.PurificationChamber, this.shard.newStack(), this.clump.newStack());
				
				// register Mekanism crystal to shard recipe
				Helpers.Mekanism.registerRecipe(RecipeType.ChemicalInjector, this.crystal.newStack(), metadata, this.shard.newStack());
				
				// register Mekanism clump to dirty dust recipe
				Helpers.Mekanism.registerRecipe(RecipeType.Crusher, this.clump.newStack(), this.dirtyDust.newStack());
				
				// register Mekanism chemical washer recipe
				Helpers.Mekanism.registerGasRecipe(RecipeType.ChemicalWasher, new GasStack(this.slurry, 1), null, new GasStack(this.cleanSlurry, 1));
				
				// register Mekanism chemical crystallizer recipe
				Helpers.Mekanism.registerGasRecipe(RecipeType.ChemicalCrystalizer, new GasStack(this.cleanSlurry, 200), null, this.crystal.newStack());
			}
			
			if (Helpers.IC2.isLoaded()) {
				// add ore washing recipe
				NBTTagCompound metadata = new NBTTagCompound();
				metadata.setInteger("amount", 1000);
				switch(this) {
				case Lead:
					Helpers.IC2.registerRecipe(RecipeType.OreWasher, this.crushedOre.newStack(), metadata, new ItemStack[] {
						this.purifiedCrushedOre.newStack(),
						DustyOres.Sulfur.tinyDust.newStack(3),
						stoneDust.newStack()	});
					break;
				default:
					Helpers.IC2.registerRecipe(RecipeType.OreWasher, this.crushedOre.newStack(), metadata, new ItemStack[] {
						this.purifiedCrushedOre.newStack(),
						this.tinyDust.newStack(2),
						stoneDust.newStack()	});
				}
			}
		}
		
		// add centrifuge recipes
		if (Helpers.IC2.isLoaded()) {
			NBTTagCompound metadata = new NBTTagCompound();
			switch (this) {
			case Adamantine:
				this.registerIC2Centrifuge(4000, MetallicOres.Iron.tinyDust.newStack());
				break;
			case Aluminium:
				this.registerIC2Centrifuge(1000, MetallicOres.Iron.tinyDust.newStack());
				break;
			case Ardite:
				this.registerIC2Centrifuge(4000, Items.dustTinyTungsten.item.newStack());
				break;
			case Brass:
				metadata.setInteger("minHeat", 2000);
				Helpers.IC2.registerRecipe(RecipeType.Centrifuge, this.dust.newStack(4), metadata, new ItemStack[] {
					MetallicOres.Copper.dust.newStack(3),
					MetallicOres.Zinc.dust.newStack()		});
				break;
			case Bronze:
				metadata.setInteger("minHeat", 2000);
				Helpers.IC2.registerRecipe(RecipeType.Centrifuge, this.dust.newStack(4), metadata, new ItemStack[] {
					MetallicOres.Copper.dust.newStack(3),
					MetallicOres.Tin.dust.newStack()		});
				break;
			case Cobalt:
				this.registerIC2Centrifuge(3000, MetallicOres.Copper.tinyDust.newStack());
				break;
			case Coldiron:
				this.registerIC2Centrifuge(1500, MetallicOres.Iron.tinyDust.newStack());
				break;
			case Electrum:
				metadata.setInteger("minHeat", 2500);
				Helpers.IC2.registerRecipe(RecipeType.Centrifuge, this.dust.newStack(2), metadata, new ItemStack[] {
					MetallicOres.Gold.dust.newStack(),
					MetallicOres.Silver.dust.newStack()		});
				break;
			case Manganese:
				this.registerIC2Centrifuge(1500, MetallicOres.Iron.tinyDust.newStack());
				break;
			case Mithril:
				this.registerIC2Centrifuge(2500, MetallicOres.Silver.tinyDust.newStack());
				break;
			case Nickel:
				this.registerIC2Centrifuge(2000, DustyOres.Sulfur.tinyDust.newStack());
				break;
			case Osmium:
				this.registerIC2Centrifuge(4000, DustyOres.Sulfur.tinyDust.newStack());
				break;
			case Platinum:
				this.registerIC2Centrifuge(3000, DustyOres.Sulfur.tinyDust.newStack());
				break;
			case Yellorium:
				this.registerIC2Centrifuge(3000, MetallicOres.Iron.tinyDust.newStack());
				break;
			case Zinc:
				this.registerIC2Centrifuge(500, DustyOres.Sulfur.tinyDust.newStack());
				break;
			default:
			}

		}
		
		// add uuMatter Scanner costs
		if (this._uuCost != 0.0D) {
			RecipeManager.addUUMatterRecipe(this.ore.source, this._uuCost);
		}
		
		// add dust smelting recipe
		RecipeManager.addSmelting(this.dust.newStack(), this.ingot.newStack(), this._smeltXP);
		
		// add tiny dust -> dust recipe
		RecipeManager.addShapedRecipe(this.dust.newStack(), "ttt", "ttt", "ttt", 't', this.tinyDustName);
		
		// add dust -> tiny dust recipe
		RecipeManager.addShapelessRecipe(this.tinyDust.newStack(9), this.dust.newStack());
		
		if (!this.isAlloy) {
			// add thaumcraft ore -> native cluster crucible recipes
			switch (this) {
			case Iron:
			case Gold:
			case Tin:
			case Copper:
			case Lead:
			case Silver:
				break;
			default:
				RecipeManager.addCrucibleRecipe("PUREIRON", this.cluster.newStack(), this.oreName, new AspectList().add(Aspect.METAL, 1).add(Aspect.ORDER, 1));
				break;
			}
			
			// add native cluster smelting
			RecipeManager.addSmelting(this.cluster.newStack(), this.ingot.newStack(2), this._smeltXP);
		}
	}
	
	private void registerIC2Centrifuge(int minHeat, ItemStack secondary) {
		OreItemStack stoneDust = new OreItemStack(new ItemStack(Helpers.IC2.getItem("itemDust"), 1, 9));
		NBTTagCompound metadata = new NBTTagCompound();
		metadata.setInteger("minHeat", minHeat);
		Helpers.IC2.registerRecipe(RecipeType.Centrifuge, this.crushedOre.newStack(), metadata, new ItemStack[] {
			this.dust.newStack(),
			secondary,
			stoneDust.newStack()
		});
		Helpers.IC2.registerRecipe(RecipeType.Centrifuge, this.purifiedCrushedOre.newStack(), metadata, new ItemStack[] {
			this.dust.newStack(),
			secondary
		});
	}

	public void registerAspects() {
	    if (!Helpers.ThaumCraft.isLoaded()) {
	        return;
	      }
	      if ((!isVanilla()) && (this != Copper) && (this != Tin) && (this != Silver) && (this != Lead)) {
	        ThaumcraftApi.registerObjectTag(this.nuggetName, new AspectList().add(Aspect.METAL, 1));
	        ThaumcraftApi.registerObjectTag(this.ingotName, new AspectList().add(Aspect.METAL, 3).add(this._secondaryAspect, 1));
	        ThaumcraftApi.registerObjectTag(this.dustName, new AspectList().add(Aspect.METAL, 2).add(Aspect.ENTROPY, 1).add(this._secondaryAspect, 1));
	        ThaumcraftApi.registerObjectTag(this.oreName, new AspectList().add(Aspect.METAL, 2).add(Aspect.EARTH, 1).add(this._secondaryAspect, 1));
	        ThaumcraftApi.registerObjectTag(this.blockName, new AspectList().add(Aspect.METAL, 5).add(this._secondaryAspect, 3));
	      }
	      ThaumcraftApi.registerObjectTag(this.netherOreName, new AspectList().add(Aspect.METAL, 2).add(this._secondaryAspect, 2).add(Aspect.EARTH, 1).add(Aspect.FIRE, 1));
	}

	@Override
	public int getTradeToAmount(Random random) {
		if (this._tradeToAmount <= 0) {
			return 0;
		}
		return this._tradeToAmount + random.nextInt(this._tradeToAmount / 4);
	}

	@Override
	public int getTradeFromAmount(Random random) {
		if (this._tradeFromAmount <= 0) {
			return 0;
		}
		return this._tradeFromAmount + random.nextInt(this._tradeFromAmount / 4);
	}

	@Override
	public void registerFluids() {
		if (FluidRegistry.isFluidRegistered(this.moltenFluidName)) {
			this.moltenFluid = FluidRegistry.getFluid(this.moltenFluidName);
			this.moltenFluidBlock = this.moltenFluid.getBlock();
			if (this.moltenFluidBlock == null) {
				this.moltenFluidBlock = new BlockOreFluid(this.moltenFluid, this.moltenFluidBlockName);
			}
			
		}
		else {
			this.moltenFluid = new OreFluid(this.moltenFluidName);
			this.moltenFluidBlock = new BlockOreFluid(this.moltenFluid, this.moltenFluidBlockName).setCreativeTab(CreativeTabs.tabMaterials);
		}
		if (FluidContainerRegistry.fillFluidContainer(new FluidStack(this.moltenFluid, 1000), new ItemStack(net.minecraft.init.Items.bucket)) == null) {
			FluidContainerRegistry.registerFluidContainer(
					new FluidStack(this.moltenFluid, 1000), 
					this.bucket.newStack(), 
					new ItemStack(net.minecraft.init.Items.bucket));
		}

	}

	@Override
	public int getLaserWeight() {
		// TODO Auto-generated method stub
		return 0;
	}
	
	static {
		mekanismOres.add(Iron);
		mekanismOres.add(Gold);
		mekanismOres.add(Osmium);
		mekanismOres.add(Copper);
		mekanismOres.add(Tin);
		mekanismOres.add(Lead);
		mekanismOres.add(Silver);
	}

	@Override
	public void registerGases() {
		// TODO Auto-generated method stub
		
	}
	
} public class OreManager implements IOreManager {
	private static HashMap<String, Block> oreList = new HashMap();
	private static HashMap<String, Item> oreItemList = new HashMap();
	
	public Block getOre(String oreName) {
		return this.oreList.get(oreName);
	}
	
	public boolean registerOre(String oreName, Block oreBlock) {
		if (this.oreList.containsKey(oreName)) {
			return false;
		}
		this.oreList.put(oreName, oreBlock);
		return true;
	}
	
	public boolean isOreRegistered(String oreName) {
		return this.oreList.containsKey(oreName);
	}

	@Override
	public boolean registerOreItem(String itemName, Item oreItem) {
		if (this.oreItemList.containsKey(itemName))
			return false;
		this.oreItemList.put(itemName, oreItem);
		return true;
	}

	@Override
	public boolean isItemRegistered(String itemName) {
		return this.oreItemList.containsKey(itemName);
	}

	@Override
	public Item getOreItem(String itemName) {
		return this.oreItemList.get(itemName);
	}
} public class RecipeManager {
	private static ICraftingHandler neiHandler;
	private static ICraftingHandler tmiHandler;
	
	private static ArrayList<ItemStack> maceratorBlackList = new ArrayList();
	private static ArrayList<ItemStack> grinderBlackList = new ArrayList();
	private static ArrayList<ItemStack> rockCrusherBlackList = new ArrayList();
	private static ArrayList<ItemStack> pulverizerBlackList = new ArrayList();
	
	public static void init() {
		Ores.grinderRecipes = new GrinderRecipeManager();
		Ores.crackerRecipes = new CrackerRecipeManager();
		
		neiHandler = new NeiHandler();
		tmiHandler = new TmiHandler();
	}
	
	public static void initRecipes() {
		maceratorBlackList.add(new ItemStack(net.minecraft.init.Items.coal, 1, 0));
		maceratorBlackList.add(new ItemStack(net.minecraft.init.Items.coal, 1, 1));

		OreItemStack bucketEmpty = new OreItemStack(net.minecraft.init.Items.bucket);
		OreItemStack coal = new OreItemStack(net.minecraft.init.Items.coal, 0);
		OreItemStack charcoal = new OreItemStack(net.minecraft.init.Items.coal, 1);
		OreItemStack chest = new OreItemStack(net.minecraft.init.Blocks.chest);
	    OreItemStack fertalizer = new OreItemStack(Helpers.Forestry.getItem("fertilizerCompound"));
		OreItemStack flint = new OreItemStack(net.minecraft.init.Items.flint);
		OreItemStack furnace = new OreItemStack(net.minecraft.init.Blocks.furnace);
		OreItemStack glass = new OreItemStack(net.minecraft.init.Blocks.glass);
		OreItemStack glassPane = new OreItemStack(net.minecraft.init.Blocks.glass_pane);
		OreItemStack gunpowder = new OreItemStack(net.minecraft.init.Items.gunpowder);
		OreItemStack oreCoal = new OreItemStack(net.minecraft.init.Blocks.coal_ore);
		OreItemStack oreLapis = new OreItemStack(net.minecraft.init.Blocks.lapis_ore);
		OreItemStack piston = new OreItemStack(net.minecraft.init.Blocks.piston);
	    OreItemStack stick = new OreItemStack(net.minecraft.init.Items.stick);
	    OreItemStack stone = new OreItemStack(net.minecraft.init.Blocks.stone);
		OreItemStack tank = new OreItemStack(Helpers.BuildCraft.getBlock("tankBlock"));
		
		if (OresPlus.config.enableMachines) {
			// machine casing
			addShapedRecipe(Items.machineCasing.item.newStack(), "sss", "sis", "sss", 's', stone.newStack(), 'i', MetallicOres.Iron.ingot.newStack());
			// cracker recipe
			if (Helpers.BuildCraft.isLoaded() && tank.source.getItem() != null) {
				addShapedRecipe(BlockManager.cracker.newStack(), "t", "c", "F", 't', tank.newStack(), 'c', Items.machineCasing.item.newStack(), 'F', furnace.newStack());
			}
			else
				addShapedRecipe(BlockManager.cracker.newStack(), "ggg", "gcg", "gFg", 'g', glass.newStack(), 'c', Items.machineCasing.item.newStack(), 'F', furnace.newStack());
			
			// grinder recipe
			addShapedRecipe(BlockManager.grinder.newStack(), "fff", "fcf", "fFf", 'f', flint.newStack(), 'c', Items.machineCasing.item.newStack(), 'F', furnace.newStack());
			
			// centrifuge recipe
			// addShapedRecipe(Blocks.centrifuge.newStack(), "ipi" "ici", "iFi", 'i', MetallicOres.Iron.ingot.newStack(), 'p', glassPane.newStack(), 'c', Items.machineCasing.newStack(), 'F', furnace.newStack());
		}
		
		//gunpowder recipe
		addShapelessRecipe(gunpowder.newStack(4), "dustSaltpeter", "dustSaltpeter", "dustCoal", "dustSulfur");
		
		// misc grinder recipes
		addGrinderRecipe(charcoal.newStack(), Items.dustCharcoal.item.newStack());
		addGrinderRecipe(coal.newStack(), Items.dustCoal.item.newStack());
		addGrinderRecipe(GeneralOres.Uranium.ore.newStack(), Items.crushedUranium.item.newStack(2));
		
		// alloy recipes
		int amount = 4;
		if (OresPlus.difficultAlloys) {
			amount = 2;
		}
		addShapelessRecipe(MetallicOres.Brass.dust.newStack(amount), "dustCopper", "dustCopper", "dustCopper", "dustZinc");
		addShapelessRecipe(MetallicOres.Bronze.dust.newStack(amount), "dustCopper", "dustCopper", "dustCopper", "dustTin");
		addShapelessRecipe(MetallicOres.Electrum.dust.newStack(2), "dustGold", "dustSilver");
		
		// misc nether ore smelting recipes
		addSmelting(GeneralOres.NetherCoal.ore.newStack(), oreCoal.newStack(2), 0.0F);
		addSmelting(GeneralOres.NetherLapis.ore.newStack(), oreLapis.newStack(2), 0.0F);
		addSmelting(GeneralOres.NetherUranium.ore.newStack(), GeneralOres.Uranium.ore.newStack(2), 0.0F);
		
	    if (Helpers.Forestry.isLoaded()) {
	        addShapelessRecipe(fertalizer.newStack(8), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName });
	        addShapelessRecipe(fertalizer.newStack(12), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName });
	        addShapelessRecipe(fertalizer.newStack(12), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName });
	        addShapelessRecipe(fertalizer.newStack(12), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName, DustyOres.Potash.dustName });
	        addShapelessRecipe(fertalizer.newStack(12), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName, Items.dustMagnesium.item.newStack() });
	        addShapelessRecipe(fertalizer.newStack(16), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName, Items.dustMagnesium.item.newStack() });
	        addShapelessRecipe(fertalizer.newStack(16), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName, Items.dustMagnesium.item.newStack() });
	        addShapelessRecipe(fertalizer.newStack(16), new Object[] { DustyOres.Saltpeter.dustName, DustyOres.Phosphorite.dustName, DustyOres.Potash.dustName, DustyOres.Potash.dustName, Items.dustMagnesium.item.newStack() });
	      }

	    addShapedRecipe(ItemManager.armorAdamantineHelmet.newStack(), "aaa", "a a", 'a', MetallicOres.Adamantine.ingotName );
	    addShapedRecipe(ItemManager.armorAdamantineChestplate.newStack(), "a a", "aaa", "aaa", 'a', MetallicOres.Adamantine.ingotName );
	    addShapedRecipe(ItemManager.armorAdamantineLeggings.newStack(), "aaa", "a a", "a a", 'a', MetallicOres.Adamantine.ingotName );
	    addShapedRecipe(ItemManager.armorAdamantineBoots.newStack(), "a a", "a a", 'a', MetallicOres.Adamantine.ingotName );
	    addShapedRecipe(ItemManager.armorColdironHelmet.newStack(), "ccc", "c c", 'c', MetallicOres.Coldiron.ingotName );
	    addShapedRecipe(ItemManager.armorColdironChestplate.newStack(), "c c", "ccc", "ccc", 'c', MetallicOres.Coldiron.ingotName );
	    addShapedRecipe(ItemManager.armorColdironLeggings.newStack(), "ccc", "c c", "c c", 'c', MetallicOres.Coldiron.ingotName );
	    addShapedRecipe(ItemManager.armorColdironBoots.newStack(), "c c", "c c", 'c', MetallicOres.Coldiron.ingotName );
	    addShapedRecipe(ItemManager.armorMithralHelmet.newStack(), "mmm", "m m", 'm', MetallicOres.Mithril.ingotName );
	    addShapedRecipe(ItemManager.armorMithralChestplate.newStack(), "m m", "mmm", "mmm", 'm', MetallicOres.Mithril.ingotName );
	    addShapedRecipe(ItemManager.armorMithralLeggings.newStack(), "mmm", "m m", "m m", 'm', MetallicOres.Mithril.ingotName );
	    addShapedRecipe(ItemManager.armorMithralBoots.newStack(), "m m", "m m", 'm', MetallicOres.Mithril.ingotName );

	    addShapedRecipe(ItemManager.toolAdamantineAxe.newStack(), " aa", " sa", " s ", 'a', MetallicOres.Adamantine.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolAdamantineHoe.newStack(), " aa", " s ", " s ", 'a', MetallicOres.Adamantine.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolAdamantinePickaxe.newStack(), "aaa", " s ", " s ", 'a', MetallicOres.Adamantine.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolAdamantineSpade.newStack(), "a", "s", "s", 'a', MetallicOres.Adamantine.ingotName, 's', stick.newStack());
	    addShapedRecipe(ItemManager.toolAdamantineSword.newStack(), "a", "a", "s", 'a', MetallicOres.Adamantine.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolColdironAxe.newStack(), " cc", " sc", " s ", 'c', MetallicOres.Coldiron.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolColdironHoe.newStack(), " cc", " s ", " s ", 'c', MetallicOres.Coldiron.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolColdironPickaxe.newStack(), "ccc", " s ", " s ", 'c', MetallicOres.Coldiron.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolColdironSpade.newStack(), "c", "s", "s", 'c', MetallicOres.Coldiron.ingotName, 's', stick.newStack());
	    addShapedRecipe(ItemManager.toolColdironSword.newStack(), "c", "c", "s", 'c', MetallicOres.Coldiron.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolMithralAxe.newStack(), " mm", " sm", " s ", 'm', MetallicOres.Mithril.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolMithralHoe.newStack(), " mm", " s ", " s ", 'm', MetallicOres.Mithril.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolMithralPickaxe.newStack(), "mmm", " s ", " s ", 'm', MetallicOres.Mithril.ingotName, 's', stick.newStack() );
	    addShapedRecipe(ItemManager.toolMithralSpade.newStack(), "m", "s", "s", 'm', MetallicOres.Mithril.ingotName, 's', stick.newStack());
	    addShapedRecipe(ItemManager.toolMithralSword.newStack(), "m", "m", "s", 'm', MetallicOres.Mithril.ingotName, 's', stick.newStack() );
	    
	    //Misc Dust Recipes
	    addShapedRecipe(Items.dustTitanium.item.newStack(), "ttt", "ttt", "ttt", 't', Items.dustTinyTitanium.item.newStack());
	    addShapedRecipe(Items.dustTungsten.item.newStack(), "ttt", "ttt", "ttt", 't', Items.dustTinyTungsten.item.newStack());
	    addShapelessRecipe(Items.dustTinyTitanium.item.newStack(9), Items.dustTitanium.item.newStack());
	    addShapelessRecipe(Items.dustTinyTungsten.item.newStack(9), Items.dustTungsten.item.newStack());
	    
		for (MetallicOres ore : MetallicOres.values()) {
			ore.registerRecipes();
		}
		
		for (GemstoneOres ore : GemstoneOres.values()) {
			ore.registerRecipes();
		}
		
		for (DustyOres ore : DustyOres.values()) {
			ore.registerRecipes();
		}
		
		for (MineralOres ore : MineralOres.values()) {
			ore.registerRecipes();
		}
		
		for (GeneralOres ore : GeneralOres.values()) {
			ore.registerRecipes();
		}
		
		for (Items item : Items.values()) {
			item.registerRecipes();
		}
		
		if (OresPlus.iridiumPlateRecipe && Helpers.IC2.isLoaded()) {
			OreItemStack iridiumPlate = new OreItemStack(Helpers.IC2.getItem("itemPartIridium"));
			OreItemStack alloyPlate = new OreItemStack(Helpers.IC2.getItem("itemPartAlloy"));
			addShapedRecipe(iridiumPlate.newStack(), "ipi", "pdp", "ipi", 'i', Items.gemIridium.toString(), 'p', alloyPlate.newStack(), 'd', GemstoneOres.Diamond.gem.newStack());
		}
		
		if (Helpers.BigReactors.isLoaded()) {
			OreItemStack graphiteBar = new OreItemStack(Helpers.BigReactors.getItem("BRIngot"), 2);
			OreItemStack fuelRod = new OreItemStack(Helpers.BigReactors.getItem("YelloriumFuelRod"));
			OreItemStack reactorCasing = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"));
			OreItemStack reactorController = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 1);
			OreItemStack reactorControlRod = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 2);
			OreItemStack reactorPowerTap = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 3);
			OreItemStack reactorAccessPort = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 4);
			OreItemStack reactorCoolantPort = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 5);
			OreItemStack reactorRedNetPort = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 6);
			//OreItemStack reactorComputerPort = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorPart"), 7);
			OreItemStack reactorRedstonePort = new OreItemStack(Helpers.BigReactors.getBlock("BRReactorRedstonePort"));
			
			addShapedRecipe(fuelRod.newStack(), "igi", "iyi", "igi", 'i', MetallicOres.Iron.ingot.newStack(), 'g', graphiteBar.newStack(), 'y', MetallicOres.Yellorium.ingot.newStack());
			addShapedRecipe(reactorCasing.newStack(4), "igi", "gyg", "igi", 'i', MetallicOres.Iron.ingot.newStack(), 'g', graphiteBar.newStack(), 'y', MetallicOres.Yellorium.ingot.newStack());
			addShapedRecipe(reactorController.newStack(), "R R", "ydy", "RrR", 'R', reactorCasing.newStack(), 'y', MetallicOres.Yellorium.ingot.newStack(), 'd', GemstoneOres.Diamond.gem.newStack(), 'r', DustyOres.Redstone.dust.newStack());
			addShapedRecipe(reactorControlRod.newStack(), "RgR", "grg", "RyR", 'R', reactorCasing.newStack(), 'g', graphiteBar.newStack(), 'r', DustyOres.Redstone.dust.newStack(), 'y', MetallicOres.Yellorium.ingot.newStack());
			addShapedRecipe(reactorPowerTap.newStack(), "RrR", "r r", "RrR", 'R', reactorCasing.newStack(), 'r', DustyOres.Redstone.dust.newStack());
			addShapedRecipe(reactorAccessPort.newStack(), "R R", " c ", "RpR", 'R', reactorCasing.newStack(), 'c', chest.newStack(), 'p', piston.newStack());
			addShapedRecipe(reactorCoolantPort.newStack(), "R R", "ibi", "RpR", 'R', reactorCasing.newStack(), 'i', MetallicOres.Iron.ingot.newStack(), 'b', bucketEmpty.newStack(), 'p', piston.newStack());
			if (Helpers.MineFactoryReloaded.isLoaded()) {
				OreItemStack redNetCable = new OreItemStack(Helpers.MineFactoryReloaded.getItem("tile.mfr.cable.redstone"));
				addShapedRecipe(reactorRedNetPort.newStack(), "RrR", "rgr", "RrR", 'R', reactorCasing.newStack(), 'r', redNetCable.newStack(), 'g', MetallicOres.Gold.ingot.newStack());
			}
			//addShapedRecipe(reactorComputerPort.newStack());
			addShapedRecipe(reactorRedstonePort.newStack(), "RrR", "rgr", "RrR", 'R', reactorCasing.newStack(), 'r', DustyOres.Redstone.dust.newStack(), 'g', MetallicOres.Gold.ingot.newStack());
		}
		
		if (Helpers.AppliedEnergistics.isLoaded()) {
			OreItemStack certusQuartzDust = new OreItemStack(Helpers.AppliedEnergistics.getItem("item.ItemMultiMaterial"), 2);
			Helpers.IC2.registerRecipe(RecipeType.Macerator, GeneralOres.CertusQuartz.ore.newStack(), certusQuartzDust.newStack(2));
		}
		
		if (Helpers.Mekanism.isLoaded()) {
			Helpers.Mekanism.registerGasRecipe(RecipeType.ElectrolyticSeperator, new FluidStack(Fluids.CopperSulfide.fluid, 2), null, new GasStack(MetallicOres.Copper.cleanSlurry, 1), new GasStack(Gases.sulfurDioxideGas.gas, 1));
			Helpers.Mekanism.registerGasRecipe(RecipeType.ChemicalCrystalizer, new GasStack(Gases.slurryCleanAntimony.gas, 200), null, Items.crystalAntimony.item.newStack());
			Helpers.Mekanism.registerGasRecipe(RecipeType.ChemicalCrystalizer, new GasStack(Gases.slurryCleanTitanium.gas, 200), null, Items.crystalTitanium.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.ChemicalInjector, Items.crystalAntimony.item.newStack(), Items.shardAntimony.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.ChemicalInjector, Items.crystalTitanium.item.newStack(), Items.shardTitanium.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.PurificationChamber, Items.shardAntimony.item.newStack(), Items.clumpAntimony.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.PurificationChamber, Items.shardTitanium.item.newStack(), Items.clumpTitanium.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.Crusher, Items.clumpAntimony.item.newStack(), Items.dustDirtyAntimony.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.Crusher, Items.clumpTitanium.item.newStack(), Items.dustDirtyTitanium.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.EnrichmentChamber, Items.dustDirtyAntimony.item.newStack(), Items.dustAntimony.item.newStack());
			Helpers.Mekanism.registerRecipe(RecipeType.EnrichmentChamber, Items.dustDirtyTitanium.item.newStack(), Items.dustTitanium.item.newStack());
		}
	}

	public static void addShapelessRecipe(ItemStack output, Object... params) {
		CraftingManager.getInstance().getRecipeList().add(new ShapelessOreRecipe(output, params));
	}

	public static void addSmelting(ItemStack input, ItemStack output, Float xp) {
		GameRegistry.addSmelting(input, output, xp);	
	}
	
	public static void addShapedRecipe (ItemStack output, Object... params) {
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(output, params));
	}

	public static void addGrinderRecipe(ItemStack input, ItemStack output) {
		// Register Grinder Recipe
		Ores.grinderRecipes.add(input, output);
		OresPlus.log.debug("Registered OresPlus:Grinder recipe for " + input.getUnlocalizedName());
		// Register IC2 Macerator Recipe
		if (Helpers.IC2.isLoaded() && !isBlackListed(maceratorBlackList, input)) {
			Helpers.IC2.registerRecipe(RecipeType.Macerator, input, output);
			OresPlus.log.debug("Registered IC2:Macerator recipe for " + input.getUnlocalizedName());
		}
		// Register AE2 Grinder Recipe
		if (Helpers.AppliedEnergistics.isLoaded() && !isBlackListed(grinderBlackList, input)) {
			NBTTagCompound metadata = new NBTTagCompound();
			metadata.setInteger("cranks", 8);
			Helpers.AppliedEnergistics.registerRecipe(RecipeType.Grinder, input, metadata, output);
			OresPlus.log.debug("Registered AE2:Grinder recipe for " + input.getUnlocalizedName());
		}
		// Register Railcraft Rock Crusher Recipe
		if (Helpers.RailCraft.isLoaded() && !isBlackListed(rockCrusherBlackList , input)) {
			Helpers.RailCraft.registerRecipe(RecipeType.RockCrusher, input, output);
			OresPlus.log.debug("Registered RailCraft:RockCrusher recipe for " + input.getUnlocalizedName());
		}
	}
	
	public static void addUUMatterRecipe(ItemStack source, double cost) {
		if (Helpers.IC2.isLoaded() && source != null && cost != 0.0) {
			NBTTagCompound metadata = new NBTTagCompound();
			metadata.setDouble("cost", cost);
			Helpers.IC2.registerRecipe(RecipeType.Scanner, source, metadata, new ItemStack[] {});
		}
	}

	private static boolean isBlackListed(
			ArrayList<ItemStack> blacklist, ItemStack input) {
		for (ItemStack item : blacklist) {
			if (item.isItemEqual(input)) {
				return true;
			}
		}
		return false;
	}

	public static void replaceRecipeResults() {
		// replace smelting results
		OresPlus.log.info("Replacing smelting results");
		Collection smeltingResultsList = FurnaceRecipes.smelting().getSmeltingList().values();
		for (Object result : smeltingResultsList.toArray()) {
			if (result instanceof ItemStack) {
				Item item = ((ItemStack)result).getItem();
				UniqueIdentifier itemUid = GameRegistry.findUniqueIdentifierFor(item);
				if (itemUid.modId != "minecraft" && itemUid.modId != References.MOD_ID) {
					OresPlus.log.info("Recipe Result " + itemUid.modId + ":" + itemUid.name);
					ItemStack newItem = new ItemStack(Ores.manager.getOreItem(itemUid.name), ((ItemStack)result).stackSize);
					if (newItem != null) {
						((ItemStack)result).func_150996_a(newItem.getItem());
						net.minecraft.init.Items.apple.setDamage(newItem, net.minecraft.init.Items.apple.getDamage(((ItemStack)result)));
					}
				}
			}
		}
	}
	
	public static void hideItem(OreItemStack item) {
		neiHandler.hideItem(item.source);
		tmiHandler.hideItem(item.source);
	}
	
	public static void addCrucibleRecipe(String key, ItemStack result, String catalyst, AspectList tags) {
		if (Helpers.ThaumCraft.isLoaded()) {
			ThaumcraftApi.addCrucibleRecipe(key, result, catalyst, tags);
		}
	}
	
} public interface IOreGenerator {
	public OreGenClass getDefaultConfig();
	
	public void registerGenerator();
	
	public WorldGenOre getOreGenerator(int dimId);
} public class OreChestLoot {
	private static String[] randomChests = { ChestGenHooks.DUNGEON_CHEST, ChestGenHooks.MINESHAFT_CORRIDOR, ChestGenHooks.PYRAMID_DESERT_CHEST, ChestGenHooks.PYRAMID_JUNGLE_CHEST, ChestGenHooks.STRONGHOLD_CORRIDOR, ChestGenHooks.STRONGHOLD_CROSSING, ChestGenHooks.STRONGHOLD_LIBRARY };

	private static OreItemStack[] commonItems = { MetallicOres.Copper.ingot, MetallicOres.Lead.ingot, MetallicOres.Nickel.ingot, MetallicOres.Silver.ingot, MetallicOres.Tin.ingot, MetallicOres.Zinc.ingot };
	private static OreItemStack[] uncommonItems = { MetallicOres.Aluminium.ingot, MetallicOres.Brass.ingot, MetallicOres.Bronze.ingot, MetallicOres.Electrum.ingot, MetallicOres.Manganese.ingot, MetallicOres.Osmium.ingot, GemstoneOres.Amethyst.gem };
	private static OreItemStack[] rareItems = { MetallicOres.Ardite.ingot, MetallicOres.Cobalt.ingot, MetallicOres.Coldiron.ingot, MetallicOres.Platinum.ingot, GemstoneOres.Peridot.gem, GemstoneOres.Ruby.gem, GemstoneOres.Sapphire.gem, GemstoneOres.Topaz.gem };
	private static OreItemStack[] ultraRareItems = { MetallicOres.Adamantine.ingot, MetallicOres.Mithril.ingot, Items.gemRedGarnet.item, Items.gemYellowGarnet.item };
	  
	private static OreItemStack[] commonSmithItems = {MetallicOres.Copper.ingot, MetallicOres.Lead.ingot, MetallicOres.Nickel.ingot, MetallicOres.Silver.ingot, MetallicOres.Tin.ingot, MetallicOres.Zinc.ingot };
	private static OreItemStack[] uncommonSmithItems = {
		MetallicOres.Aluminium.ingot, MetallicOres.Brass.ingot, MetallicOres.Electrum.ingot, MetallicOres.Manganese.ingot, MetallicOres.Osmium.ingot,
		ItemManager.toolAdamantineAxe, ItemManager.toolAdamantineHoe, ItemManager.toolAdamantinePickaxe, ItemManager.toolAdamantineSpade,
		ItemManager.toolColdironAxe, ItemManager.toolColdironHoe, ItemManager.toolColdironPickaxe, ItemManager.toolColdironSpade,
		ItemManager.toolMithralAxe, ItemManager.toolMithralHoe, ItemManager.toolMithralPickaxe, ItemManager.toolMithralSpade};
	private static OreItemStack[] rareSmithItems = {
		MetallicOres.Adamantine.ingot, MetallicOres.Ardite.ingot, MetallicOres.Cobalt.ingot, MetallicOres.Coldiron.ingot, MetallicOres.Mithril.ingot, MetallicOres.Platinum.ingot,
		ItemManager.toolAdamantineSword, ItemManager.toolColdironSword, ItemManager.toolMithralSword};
	private static OreItemStack[] ultraRareSmithItems = {
		ItemManager.armorAdamantineBoots, ItemManager.armorAdamantineChestplate, ItemManager.armorAdamantineHelmet, ItemManager.armorAdamantineLeggings,
		ItemManager.armorColdironBoots, ItemManager.armorColdironChestplate, ItemManager.armorColdironHelmet, ItemManager.armorColdironLeggings,
		ItemManager.armorMithralBoots, ItemManager.armorMithralChestplate, ItemManager.armorMithralHelmet, ItemManager.armorMithralLeggings};

	public static void registerChestLoot() {
	    Random rand = new Random();

	    for (String chest : randomChests) {
	    	for (OreItemStack item : commonItems)
	    		ChestGenHooks.addItem(chest, new WeightedRandomChestContent(item.newStack(2 + rand.nextInt(4)), 1, 3, 5));

	    	for (OreItemStack item : uncommonItems)
	    		ChestGenHooks.addItem(chest, new WeightedRandomChestContent(item.newStack(1 + rand.nextInt(4)), 1, 2, 4));

	    	for (OreItemStack item : rareItems)
	    		ChestGenHooks.addItem(chest, new WeightedRandomChestContent(item.newStack(), 1, 1, 2));

	    	for (OreItemStack item : ultraRareItems)
	    		ChestGenHooks.addItem(chest, new WeightedRandomChestContent(item.newStack(), 1, 1, 1));
	    }
	    for (OreItemStack item : commonSmithItems)
	    	ChestGenHooks.addItem(ChestGenHooks.VILLAGE_BLACKSMITH, new WeightedRandomChestContent(item.newStack(2 + rand.nextInt(4)), 1, 3, 5));
	      
	    for (OreItemStack item : uncommonSmithItems)
	    	ChestGenHooks.addItem(ChestGenHooks.VILLAGE_BLACKSMITH, new WeightedRandomChestContent(item.newStack(1 + rand.nextInt(4)), 1, 2, 4));
	      
	    for (OreItemStack item : rareSmithItems)
	    	ChestGenHooks.addItem(ChestGenHooks.VILLAGE_BLACKSMITH, new WeightedRandomChestContent(item.newStack(), 1, 1, 2));
	      
	    for (OreItemStack item : ultraRareSmithItems)
	    	ChestGenHooks.addItem(ChestGenHooks.VILLAGE_BLACKSMITH, new WeightedRandomChestContent(item.newStack(), 1, 1, 1));
	}
} public class OreGenClass {
	public String name;
	public String oreName;
	public boolean enabled;
	public int dimension;
	public int numVeins;
	public int veinSize;
	public int minY;
	public int maxY;
	public boolean doRegen;
	public OreGenType genType;
	public int density;
	public String regenKey;
	
	public OreGenClass(String name, String oreName, boolean en, int dim, int num, int size, 
			int min, int max, boolean regen, OreGenType oreGenType, int oreDensity, String regenKey) {
		this.name = name;
		this.oreName = oreName;
		this.enabled = en;
		this.dimension = dim;
		this.numVeins = num;
		this.veinSize = size;
		this.minY = min;
		this.maxY = max;
		this.doRegen = regen;
		this.genType = oreGenType;
		this.density = oreDensity;
		this.regenKey = regenKey;
	}

} public enum OreGenerators implements IOreGenerator {
	Adamantine("oreAdamantine", 0, 1, 4, 0, 25),
	Aluminium("oreAluminium", 0, 3, 6, 0, 64),
	Amethyst("oreAmethyst", 0, 6, 6, 0, 40),
	Apatite("oreApatite", 0, 6, 6, 25, 50),
	Bauxite("oreBauxite", 0, 2, 16, 32, 80),
	BauxiteHigh("oreBauxite", 0, 3, 16, 70, 220),
	Bitumen("oreBitumen", 0, 4, 4, 0, 60),
	Cassiterite("oreCassiterite", 0, 1, 32, 32, 70),
	CassiteriteHigh("oreCassiterite", 0, 1, 32, 70, 220),
	CertusQuartz("oreCertusQuartz", 0, 8, 4, 12, 72),
	Coal("oreCoal", 0, 20, 16, 0, 128),
	Coldiron("oreColdiron", 0, 4, 6, 0, 45),
	Copper("oreCopper", 0, 18, 8, 10, 60),
	CopperHigh("oreCopper", 0, 12, 10, 60, 220),
	Diamond("oreDiamond", 0, 1, 7, 0, 16),
	Galena("oreGalena", 0, 1, 16, 0, 32),
	Gold("oreGold", 0, 2, 8, 0, 32),
	GreenSapphire("oreGreenSapphire", 0, 4, 6, 0, 40),
	Iridium("oreIridium", 0, 1, 1, 0, 50),
	Iron("oreIron", 0, 20, 8, 0, 128),
	Lapis("oreLapis", 0, 1, 6, 16, 32),
	Lead("oreLead", 0, 4, 8, 10, 45),
	Magnesium("oreMagnesium", 0, 4, 4, 0, 140),
	Malachite("oreMalachite", 0, 4, 6, 0, 40),
	Manganese("oreManganese", 0, 5, 5, 0, 140),
	Mithral("oreMithral", 0, 3, 3, 0, 140),
	Nickel("oreNickel", 0, 4, 8, 5, 25),
	Nikolite("oreNikolite", 0, 4, 10, 0, 15),
	Osmium("oreOsmium", 0, 12, 8, 0, 60),
	Phosporite("orePhosphorite", 0, 4, 4, 0, 140),
	Platinum("orePlatinum", 0, 3, 4, 0, 30),
	Potash("orePotash", 0, 4, 4, 0, 140),
	Redstone("oreRedstone", 0, 8, 7, 0, 16),
	Ruby("oreRuby", 0, 4, 6, 0, 40),
	Saltpeter("oreSaltpeter", 0, 8, 8, 50, 60),
	Sapphire("oreSapphire", 0, 4, 6, 0, 40),
	Silver("oreSilver", 0, 6, 8, 0, 40),
	SphaleriteOverworld("oreSphalerite", 0, 8, 1, 2, 10, OreGenType.UNDER_LAVA),
	Sulfur("oreSulfur", 0, 8, 10, 6, 15, OreGenType.NEAR_LAVA),
	Tanzanite("oreTanzanite", 0, 4, 6, 0, 40),
	Tetrahedrite("oreTetrahedrite", 0, 1, 32, 32, 70),
	TetrahedriteHigh("oreTetrahedrite", 0, 1, 32, 70, 220),
	Tin("oreTin", 0, 12, 10, 12, 56),
	Topaz("oreTopaz", 0, 4, 6, 0, 40),
	Tungsten("oreTungsten", 0, 1, 4, 0, 15),
	Uranium("oreUranium", 0, 20, 3, 0, 62),
	Yellorite("oreYellorium", 0, 5, 10, 0, 50),
	Zinc("oreZinc", 0, 6, 5, 0, 140);
	
	private String _oreName;
	private boolean _enabled;
	private int _dimension;
	private int _numVeins;
	private int _veinSize;
	private int _minY;
	private int _maxY;
	private boolean _enableRegen;
	private OreGenType _genType;
	private int _density;
	
	public WorldGenOre generator;
	
	private HashMap<Integer, WorldGenOre> generators = new HashMap();
	
	private OreGenerators(String oreName, int dimension, int numVeins, 
			int veinSize, int minY, int maxY) {
		this(oreName, dimension, numVeins, veinSize, minY, maxY, OreGenType.NORMAL);
	}
	
	private OreGenerators(String oreName, int dimension, int numVeins,
			int veinSize, int minY, int maxY, OreGenType genType) {
		this._oreName = oreName;
		this._enabled = true;
		this._dimension = dimension;
		this._numVeins = numVeins;
		this._veinSize = veinSize;
		this._minY = minY;
		this._maxY = maxY;
		this._enableRegen = false;
		this._genType = genType;
		this._density = 100;
	}
	
	
	public OreGenClass getDefaultConfig() {
		return new OreGenClass(this.name(), this._oreName, this._enabled, 
				this._dimension, this._numVeins, this._veinSize, this._minY, 
				this._maxY, this._enableRegen, this._genType, this._density, "DISABLED");
	}
	
	public void registerGenerator() {
		this.generator = this.registerGenerator(0);
	}
	
	private WorldGenOre registerGenerator(int dimId) {
		OreGenClass oreGen = ConfigOreGen.getOreGeneratorConfig(getDefaultConfig(), dimId);
		if (this._enabled && Ores.manager.isOreRegistered(this._oreName)) { 
			WorldGenOre gen = new WorldGenOre(oreGen);
			this.generators.put(dimId, gen);
			return gen;
		}
		else {
			return null;
		}
	}

	@Override
	public WorldGenOre getOreGenerator(int dimId) {
		if (this.generators.get(dimId) == null) {
			this.registerGenerator(dimId);
		}
		return this.generators.get(dimId);
	}
} public enum OreGeneratorsEnd implements IOreGenerator {
	Cooperite("oreSheldonite", 1, 1, 4, 0, 127),
	Olivine("oreOlivine", 1, 5, 8, 0, 127),
	Sodalite("oreSodalite", 1, 8, 16, 0, 127),
	Tungstate("oreTungstate", 1, 4, 16, 0, 127);
	
	private String _oreName;
	private boolean _enabled;
	private int _dimension;
	private int _numVeins;
	private int _veinSize;
	private int _minY;
	private int _maxY;
	private boolean _enableRegen;
	private OreGenType _genType;
	private int _density;
	
	public WorldGenOre generator;
	
	private OreGeneratorsEnd(String oreName, int dimension, int numVeins, 
			int veinSize, int minY, int maxY) {
		this(oreName, dimension, numVeins, veinSize, minY, maxY, OreGenType.NORMAL);
	}
	
	private OreGeneratorsEnd(String oreName, int dimension, int numVeins,
			int veinSize, int minY, int maxY, OreGenType genType) {
		this._oreName = oreName;
		this._enabled = true;
		this._dimension = dimension;
		this._numVeins = numVeins;
		this._veinSize = veinSize;
		this._minY = minY;
		this._maxY = maxY;
		this._enableRegen = false;
		this._genType = genType;
		this._density = 100;
	}
	
	
	public OreGenClass getDefaultConfig() {
		return new OreGenClass(this.name(), this._oreName, this._enabled, 
				this._dimension, this._numVeins, this._veinSize, this._minY, 
				this._maxY, this._enableRegen, this._genType, this._density, "DISABLED");
	}
	
	public void registerGenerator() {
		OreGenClass oreGen = ConfigOreGen.getEndOreGeneratorConfig(getDefaultConfig());
		if (this._enabled && Ores.manager.isOreRegistered(this._oreName)) 
			this.generator = new WorldGenOre(oreGen);
	}

	@Override
	public WorldGenOre getOreGenerator(int dimId) {
		if (this.generator == null) {
			this.registerGenerator();
		}
		return this.generator;
	}
} public enum OreGeneratorsNether implements IOreGenerator {
	CinnabarSmallest("oreCinnabar", -1, 16, 4, 64, 128),
	CinnabarSmall("oreCinnabar", -1, 8, 8, 64, 128),
	Cinnabar("oreCinnabar", -1, 4, 12, 64, 128),
	CinnabarLarge("oreCinnabar", -1, 2, 24, 64, 128),
	CinnabarLargest("oreCinnabar", -1, 1, 32, 64, 128),
	NetherArdite("oreNetherArdite", -1, 8, 3, 32, 96),
	NetherCoal("oreNetherCoal", -1, 8, 16, 1, 126),
	NetherCobalt("oreNetherCobalt", -1, 8, 3, 32, 96),
	NetherCopper("oreNetherCopper", -1, 8, 8, 1, 126),
	NetherDiamond("oreNetherDiamond", -1, 4, 3, 1, 126),
	NetherEmerald("oreNetherEmerald", -1, 3, 2, 1, 126),
	NetherGold("oreNetherGold", -1, 8, 6, 1, 126),
	NetherIron("oreNetherIron", -1, 8, 8, 1, 126),
	NwtherLapis("oreNetherLapis", -1, 8, 6, 1, 126),
	NetherLead("oreNetherLead", -1, 6, 6, 1, 126),
	NetherNikolite("oreNetherNikolite", -1, 8, 4, 1, 126),
	NetherRedstone("oreNetherRedstone", -1, 6, 8, 1, 126),
	NetherSilver("oreNetherSilver", -1, 6, 4, 1, 126),
	NetherTin("oreNetherTin", -1, 8, 8, 1, 126),
	NetherUranium("oreNetherUranium", -1, 3, 2, 1, 126),
	PyriteSmallest("orePyrite", -1, 16, 4, 0, 64),
	PyriteSmall("orePyrite", -1, 8, 8, 0, 64),
	Pyrite("orePyrite", -1, 4, 12, 0, 64),
	PyriteLarge("orePyrite", -1, 2, 24, 0, 64),
	PyriteLargest("orePyrite", -1, 1, 32, 0, 64),
	Quartz("oreQuartz", -1, 16, 13, 10, 118),
	SphaleriteSmallest("oreSphalerite", -1, 16, 4, 32, 96),
	SphaleriteSmall("oreSphalerite", -1, 8, 8, 32, 96),
	Sphalerite("oreSphalerite", -1, 4, 12, 32, 96),
	SphaleriteLarge("oreSphalerite", -1, 2, 24, 32, 96),
	SphaleriteLargest("oreSphalerite", -1, 1, 32, 32, 96);
	
	private String _oreName;
	private boolean _enabled;
	private int _dimension;
	private int _numVeins;
	private int _veinSize;
	private int _minY;
	private int _maxY;
	private boolean _enableRegen;
	private OreGenType _genType;
	private int _density;
	
	public WorldGenOre generator;
	
	private OreGeneratorsNether(String oreName, int dimension, int numVeins, 
			int veinSize, int minY, int maxY) {
		this(oreName, dimension, numVeins, veinSize, minY, maxY, OreGenType.NORMAL);
	}
	
	private OreGeneratorsNether(String oreName, int dimension, int numVeins,
			int veinSize, int minY, int maxY, OreGenType genType) {
		this._oreName = oreName;
		this._enabled = true;
		this._dimension = dimension;
		this._numVeins = numVeins;
		this._veinSize = veinSize;
		this._minY = minY;
		this._maxY = maxY;
		this._enableRegen = false;
		this._genType = genType;
		this._density = 100;
	}
	
	
	public OreGenClass getDefaultConfig() {
		return new OreGenClass(this.name(), this._oreName, this._enabled, 
				this._dimension, this._numVeins, this._veinSize, this._minY, 
				this._maxY, this._enableRegen, this._genType, this._density, "DISABLED");
	}
	
	public void registerGenerator() {
		OreGenClass oreGen = ConfigOreGen.getNetherOreGeneratorConfig(getDefaultConfig());
		if (this._enabled && Ores.manager.isOreRegistered(this._oreName)) 
			this.generator = new WorldGenOre(oreGen);
	}

	@Override
	public WorldGenOre getOreGenerator(int dimId) {
		if (this.generator == null) {
			this.registerGenerator();
		}
		return this.generator;
	}
} public class VillagerTradeHandler implements IVillageTradeHandler {
	public static final int VILLAGER_FARMER = 0;
	public static final int VILLAGER_LIBRARIAN = 1;
	public static final int VILLAGER_PRIEST = 2;
	public static final int VILLAGER_BLACKSMITH = 3;
	public static final int VILLAGER_BUTCHER = 4;

	private int _villagerID;
	
	public VillagerTradeHandler(int villagerID) {
		this._villagerID = villagerID;
	}
	
	@Override
	public void manipulateTradesForVillager(EntityVillager villager,
			MerchantRecipeList recipeList, Random random) {
		switch (this._villagerID) {
		case VILLAGER_BLACKSMITH:
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorAdamantineBoots, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorAdamantineChestplate, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorAdamantineHelmet, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorAdamantineLeggings, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolAdamantineAxe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolAdamantineHoe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolAdamantinePickaxe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolAdamantineSpade, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolAdamantineSword, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorColdironBoots, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorColdironChestplate, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorColdironHelmet, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorColdironLeggings, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolColdironAxe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolColdironHoe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolColdironPickaxe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolColdironSpade, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolColdironSword, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorMithralBoots, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorMithralChestplate, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorMithralHelmet, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.armorMithralLeggings, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolMithralAxe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolMithralHoe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolMithralPickaxe, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolMithralSpade, random));
			recipeList.add(this.getMerchantRecipeFor(ItemManager.toolMithralSword, random));
			int tradeAmount;
			for (MetallicOres ore : MetallicOres.values()) {
				tradeAmount = ore.getTradeToAmount(random);
				if (tradeAmount > 0) {
					recipeList.add(new MerchantRecipe(ore.ingot.newStack(tradeAmount), GemstoneOres.Emerald.gem.newStack()));
				}
				tradeAmount = ore.getTradeFromAmount(random);
				if (tradeAmount > 0) {
					recipeList.add(new MerchantRecipe(GemstoneOres.Emerald.gem.newStack(), ore.ingot.newStack(tradeAmount)));
				}
			}
			break;
		default:
		}
	}
	
	private MerchantRecipe getMerchantRecipeFor(OreItemStack item, Random random) {
		int itemTypeCost = 0;
		int materialCost = 0;
		Item source = item.source.getItem();
		if (source instanceof OreArmor) {
			switch (((OreArmor)source).armorType) {
			case 1:
				materialCost = 5;
				break;
			case 2:
				materialCost = 4;
				break;
			default:
				materialCost = 3;
			}
			itemTypeCost = 5;
			ArmorMaterial material = ((OreArmor)source).getArmorMaterial();
			if (material == ItemManager.armorAdamantine) {
				materialCost = 5;
			} 
			else if (material == ItemManager.armorColdiron) {
				materialCost = 1;
			}
			else if (material == ItemManager.armorMithral) {
				materialCost = 3;
			}
		}
		else if (source instanceof ItemTool) {
			if (source instanceof OreAxe) {
				itemTypeCost = 4;
			} else if (source instanceof OreHoe) {
				itemTypeCost = 3;
			} else if (source instanceof OrePickaxe) {
				itemTypeCost = 4;
			} else if (source instanceof OreSpade) {
				itemTypeCost = 4;
			} else if (source instanceof OreSword) {
				itemTypeCost = 5;
			}
			ToolMaterial material = ((ItemTool)source).func_150913_i();
			if (material == ItemManager.toolAdamantine) {
				materialCost = 5;
			}
			else if (material == ItemManager.toolColdiron) {
				materialCost = 1;
			}
			else if (material == ItemManager.toolMithral) {
				materialCost = 3;
			}
		}
		
		if (itemTypeCost == 0 || materialCost == 0)
			return null;
		
		int tradeAmount = itemTypeCost + materialCost;
		return new MerchantRecipe(GemstoneOres.Emerald.gem.newStack(tradeAmount + random.nextInt(tradeAmount) / 3), item.newStack());
	}
} public class WorldGenCore 
implements IWorldGenerator {
	public static HashMap<Integer, ArrayList<WorldGenOre>> oreGenerators = new HashMap();
	
	public static Collection<String> biomeListBauxite = new ArrayList();
	public static Collection<String> biomeListCassiterite = new ArrayList();
	public static Collection<String> biomeListColdiron = new ArrayList();
	public static Collection<String> biomeListMithral = new ArrayList();
	public static Collection<String> biomeListNickel = new ArrayList();
	public static Collection<String> biomeListRuby = new ArrayList();
	public static Collection<String> biomeListSapphire = new ArrayList();
	public static Collection<String> biomeListSaltpeter = new ArrayList();
	public static Collection<String> biomeListSulfur = new ArrayList();
	public static Collection<String> biomeListTetrahedrite = new ArrayList();
	public static Collection<String> biomeListTanzanite = new ArrayList();
	public static Collection<String> biomeListMalachite = new ArrayList();
	
	public WorldGenCore(){
		
		GameRegistry.registerWorldGenerator(this, 1);
	}

	public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider){
		doWorldGen(random, world, chunkX, chunkZ, true);
	}
	
	public void doWorldGen(Random random, World world, int chunkX, int chunkZ, boolean newChunk) {
		ArrayList<WorldGenOre> oreGens = oreGenerators.get(world.provider.dimensionId);
		if (oreGens == null)
			return;
		for (WorldGenOre oreGen : oreGens) {
			if (oreGen != null)
				oreGen.generate(world, random, chunkX * 16, chunkZ * 16);
		}
	}

	static {
		biomeListBauxite.add(BiomeGenBase.plains.biomeName);
		biomeListBauxite.add(BiomeGenBase.forest.biomeName);
		biomeListBauxite.add(BiomeGenBase.forestHills.biomeName);
		biomeListCassiterite.add(BiomeGenBase.taiga.biomeName);
		biomeListCassiterite.add(BiomeGenBase.taigaHills.biomeName);
		biomeListCassiterite.add(BiomeGenBase.icePlains.biomeName);
		biomeListCassiterite.add(BiomeGenBase.iceMountains.biomeName);
		biomeListCassiterite.add(BiomeGenBase.mushroomIsland.biomeName);
		biomeListCassiterite.add(BiomeGenBase.mushroomIslandShore.biomeName);
		biomeListCassiterite.add(BiomeGenBase.extremeHills.biomeName);
		biomeListCassiterite.add(BiomeGenBase.extremeHillsEdge.biomeName);
		biomeListColdiron.add(BiomeGenBase.frozenOcean.biomeName);
		biomeListColdiron.add(BiomeGenBase.frozenRiver.biomeName);
		biomeListColdiron.add(BiomeGenBase.icePlains.biomeName);
		//biomeListColdiron.add(BiomeGenBase.icePlainsSpikes.biomeName);
		biomeListColdiron.add(BiomeGenBase.iceMountains.biomeName);
		//biomeListColdiron.add(BiomeGenBase.coldBeach.biomeName);
		biomeListColdiron.add(BiomeGenBase.coldTaiga.biomeName); // Cold Taiga
		biomeListColdiron.add(BiomeGenBase.coldTaigaHills.biomeName); // Cold Taiga Hills
		//biomeListColdiron.add(BiomeGenBase.coldTaigaM.biomeName);
		biomeListColdiron.add(BiomeGenBase.extremeHills.biomeName);
		biomeListColdiron.add(BiomeGenBase.extremeHillsEdge.biomeName);
		//biomeListColdiron.add(BiomeGenBase.extremeHillsM.biomeName);
		biomeListColdiron.add(BiomeGenBase.taiga.biomeName);
		biomeListColdiron.add(BiomeGenBase.taigaHills.biomeName);
		//biomeListColdiron.add(BiomeGenBase.taigM.biomeName);
		biomeListColdiron.add(BiomeGenBase.megaTaiga.biomeName); // Mega Taiga
		biomeListColdiron.add(BiomeGenBase.megaTaigaHills.biomeName); // Mega Taiga Hills
		//biomeListColdiron.add(BiomeGenBase.megaSpruceTaiga.biomeName);
		biomeListColdiron.add(BiomeGenBase.extremeHillsPlus.biomeName); // Extreme Hills +
		//biomeListColdiron.add(BiomeGenBase.extremeHillsPlusM.biomeName);
		//biomeListColdiron.add(BiomeGenBase.stoneBeach.biomeName);
		biomeListMithral.add(BiomeGenBase.extremeHills.biomeName);
		biomeListMithral.add(BiomeGenBase.extremeHillsEdge.biomeName);
		biomeListNickel.add(BiomeGenBase.extremeHills.biomeName);
		biomeListNickel.add(BiomeGenBase.extremeHillsEdge.biomeName);
		biomeListRuby.add(BiomeGenBase.desert.biomeName);
		biomeListRuby.add(BiomeGenBase.desertHills.biomeName);
		biomeListSaltpeter.add(BiomeGenBase.desert.biomeName);
		biomeListSaltpeter.add(BiomeGenBase.desertHills.biomeName);
		biomeListSapphire.add(BiomeGenBase.beach.biomeName);
		biomeListSapphire.add(BiomeGenBase.ocean.biomeName);
		biomeListSulfur.add(BiomeGenBase.extremeHills.biomeName);
		biomeListSulfur.add(BiomeGenBase.extremeHillsEdge.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.jungle.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.jungleHills.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.swampland.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.mushroomIsland.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.mushroomIslandShore.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.extremeHills.biomeName);
		biomeListTetrahedrite.add(BiomeGenBase.extremeHillsEdge.biomeName);
		biomeListMalachite.add(BiomeGenBase.swampland.biomeName);
		biomeListTanzanite.add(BiomeGenBase.coldBeach.biomeName);
		biomeListTanzanite.add(BiomeGenBase.coldTaiga.biomeName);
		biomeListTanzanite.add(BiomeGenBase.coldTaigaHills.biomeName);
		biomeListTanzanite.add(BiomeGenBase.frozenOcean.biomeName);
		biomeListTanzanite.add(BiomeGenBase.frozenRiver.biomeName);
		biomeListTanzanite.add(BiomeGenBase.iceMountains.biomeName);
		biomeListTanzanite.add(BiomeGenBase.icePlains.biomeName);
		biomeListTanzanite.add(BiomeGenBase.megaTaiga.biomeName);
		biomeListTanzanite.add(BiomeGenBase.megaTaigaHills.biomeName);
		biomeListTanzanite.add(BiomeGenBase.taiga.biomeName);
		biomeListTanzanite.add(BiomeGenBase.taigaHills.biomeName);
	}
} public class WorldGenOre {
	private OreGenClass ore;
	boolean enabled = true;	// generation of ore enabled
	Block block;		// block to generate
	Block target;
	public boolean doRegen;
	public String regenKey;
	public int dimension;
	public Collection<String> biomeList;
	public HashMap<Integer, ArrayList<ChunkCoordIntPair>> regenList = new HashMap();

	public WorldGenOre(OreGenClass genOre) {
		this.ore = genOre;
		this.block = Ores.manager.getOre(genOre.oreName);
		this.doRegen = genOre.doRegen;
		this.regenKey = genOre.regenKey;
		this.dimension = genOre.dimension;
		switch(genOre.dimension)
		{
		case -1:
			target = net.minecraft.init.Blocks.netherrack;
			break;
		case 1:
			target = net.minecraft.init.Blocks.end_stone;
			break;
		default:
			target = net.minecraft.init.Blocks.stone;
		}
		
		if (ore.oreName.equals("oreBauxite"))
			this.biomeList = WorldGenCore.biomeListBauxite;
		else if (ore.oreName.equals("oreCassiterite"))
			this.biomeList = WorldGenCore.biomeListCassiterite;
		else if (ore.oreName.equals("oreColdiron"))
			this.biomeList = WorldGenCore.biomeListColdiron;
		else if (ore.oreName.equals("oreMithral"))
			this.biomeList = WorldGenCore.biomeListMithral;
		else if (ore.oreName.equals("oreNickel"))
			this.biomeList = WorldGenCore.biomeListNickel;
		else if (ore.oreName.equals("oreRuby"))
			this.biomeList = WorldGenCore.biomeListRuby;
		else if (ore.oreName.equals("oreSapphire"))
			this.biomeList = WorldGenCore.biomeListSapphire;
		else if (ore.oreName.equals("oreSaltpeter"))
			this.biomeList = WorldGenCore.biomeListSaltpeter;
		else if (ore.oreName.equals("oreTetrahedrite"))
			this.biomeList = WorldGenCore.biomeListTetrahedrite;
		else if (ore.oreName.equals("oreMalachite"))
			this.biomeList = WorldGenCore.biomeListMalachite;
		else if (ore.oreName.equals("oreTanzanite"))
			this.biomeList = WorldGenCore.biomeListTanzanite;
		else
			this.biomeList = new ArrayList();
	}

	public boolean generate(World world, Random random, int chunkX, int chunkZ){
		int biomeX = chunkX * 16 + 8;
		int biomeZ = chunkZ * 16 + 8;
		String biomeName = world.getBiomeGenForCoords(biomeX, biomeZ).biomeName;
		if (!ore.enabled)
			return false;
		if (this.biomeList.isEmpty() || this.biomeList.contains(biomeName)) {
			int actualVeins = this.ore.numVeins * this.ore.density / 100;
			int seaLevel = world.provider.getAverageGroundLevel() + 1;
			for (int a=0; a<actualVeins; a++){
				int x = chunkX + random.nextInt(16);
				int y = (random.nextInt(this.ore.maxY - this.ore.minY) + this.ore.minY) * seaLevel / 64;
				int z = chunkZ + random.nextInt(16);
				
				switch (ore.veinSize) {
				case 1:
					if (world.getBlock(x, y, z).isReplaceableOreGen(world, x, y, z, this.target)) {
						switch (ore.genType) {
						case NEAR_LAVA:
							if (isNearLava(world, x, y, z))
								world.setBlock(x, y, z, this.block, 0, 2);
							break;
						case UNDER_LAVA:
							if (world.getBlock(x, y + 1, z).equals(net.minecraft.init.Blocks.lava))
								world.setBlock(x, y, z, this.block, 0, 2);
							break;
						default:
							world.setBlock(x, y, z, this.block, 0, 2);
						}
					}
					break;
				default:
					float f = random.nextFloat() * (float)Math.PI;
					double d0 = (double)((float)(x + 8) + MathHelper.sin(f) * (float)this.ore.veinSize / 8.0F);
					double d1 = (double)((float)(x + 8) - MathHelper.sin(f) * (float)this.ore.veinSize / 8.0F);
					double d2 = (double)((float)(z + 8) + MathHelper.cos(f) * (float)this.ore.veinSize / 8.0F);
					double d3 = (double)((float)(z + 8) - MathHelper.cos(f) * (float)this.ore.veinSize / 8.0F);
					double d4 = (double)(y + random.nextInt(3) - 2);
					double d5 = (double)(y + random.nextInt(3) - 2);
					
					for (int l = 0; l <= this.ore.veinSize; ++l) {
						double d6 = d0 + (d1 - d0) * (double)l / (double)this.ore.veinSize;
						double d7 = d4 + (d5 - d4) * (double)l / (double)this.ore.veinSize;
						double d8 = d2 + (d3 - d2) * (double)l / (double)this.ore.veinSize;
						double d9 = random.nextDouble() * (double)this.ore.veinSize / 16.0D;
						double d10 = (double)(MathHelper.sin((float)l * (float)Math.PI / (float)this.ore.veinSize) + 1.0F) * d9 + 1.0D;
						double d11 = (double)(MathHelper.sin((float)l * (float)Math.PI / (float)this.ore.veinSize) + 1.0F) * d9 + 1.0D;
						int i1 = MathHelper.floor_double(d6 - d10 / 2.0D);
						int j1 = MathHelper.floor_double(d7 - d11 / 2.0D);
						int k1 = MathHelper.floor_double(d8 - d10 / 2.0D);
						int l1 = MathHelper.floor_double(d6 + d10 / 2.0D);
						int i2 = MathHelper.floor_double(d7 + d11 / 2.0D);
						int j2 = MathHelper.floor_double(d8 + d10 / 2.0D);
						
						for (int k2 = i1; k2 <= l1; ++k2) {
							double d12 = ((double)k2 + 0.5D - d6) / (d10 / 2.0D);
							if (d12 * d12 < 1.0D) {
								for (int l2 = j1; l2 <= i2; ++l2) {
									double d13 = ((double)l2 + 0.5D - d7) / (d11 / 2.0D);
									if (d12 * d12 + d13 * d13 < 1.0D) {
										for (int i3 = k1; i3 <= j2; ++i3) {
											double d14 = ((double)i3 + 0.5D - d8) / (d10 / 2.0D);
											if (d12 * d12 + d13 * d13 + d14 * d14 < 1.0F && world.getBlock(k2,  l2,  i3).isReplaceableOreGen(world, k2,  l2,  i3, this.target)) {
												switch(this.ore.genType) {
												case NEAR_LAVA:
													if (isNearLava(world, k2, l2, i3))
														world.setBlock(k2, l2, i3, this.block, 0, 2);
													break;
												case UNDER_LAVA:
													if (world.getBlock(k2, l2 + 1, i3).equals(net.minecraft.init.Blocks.lava))
														world.setBlock(k2, l2, i3, this.block, 0, 2);
													break;
												default:
													world.setBlock(k2, l2, i3, this.block, 0, 2);
												}
											}
										}
									}
								}
							}
						}
					}
				}
				
			}
			return true;
		}
		else
			return false;
	}

	public String getOreName() {
		return this.ore.name;
	}
		
	private boolean isNearLava(World world, int nearX, int nearY, int nearZ) {
		for (int k = 1; k <= 4; k++) {
			if (world.getBlock(nearX, nearY - k, nearZ).equals(net.minecraft.init.Blocks.lava))
				return true;
			if (!world.getBlock(nearX, nearY - k, nearZ).isAir(world, nearX, nearY - k, nearZ))
				return false;
		}
		return false;
	}
}
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.oredict.OreDictionary;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLInterModComms;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.event.FMLModIdMappingEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.VillagerRegistry;
import tw.oresplus.api.Ores;
import tw.oresplus.blocks.BlockCore;
import tw.oresplus.blocks.BlockOre;
import tw.oresplus.blocks.BlockManager;
import tw.oresplus.blocks.TileEntityCracker;
import tw.oresplus.blocks.TileEntityGrinder;
import tw.oresplus.core.BucketHandler;
import tw.oresplus.core.GuiHandler;
import tw.oresplus.core.IMCHandler;
import tw.oresplus.core.IProxy;
import tw.oresplus.core.ItemMapHelper;
import tw.oresplus.core.OreEventHandler;
import tw.oresplus.core.OreLog;
import tw.oresplus.core.References;
import tw.oresplus.core.TickHandler;
import tw.oresplus.core.config.ConfigCore;
import tw.oresplus.core.config.ConfigMain;
import tw.oresplus.core.helpers.AppEngHelper;
import tw.oresplus.core.helpers.BCHelper;
import tw.oresplus.core.helpers.Helpers;
import tw.oresplus.fluids.FluidManager;
import tw.oresplus.gases.GasManager;
import tw.oresplus.items.ItemCore;
import tw.oresplus.items.ItemManager;
import tw.oresplus.items.Items;
import tw.oresplus.network.NetHandler;
import tw.oresplus.ores.MetallicOres;
import tw.oresplus.ores.OreManager;
import tw.oresplus.recipes.RecipeManager;
import tw.oresplus.worldgen.IOreGenerator;
import tw.oresplus.worldgen.OreChestLoot;
import tw.oresplus.worldgen.OreGenClass;
import tw.oresplus.worldgen.OreGenerators;
import tw.oresplus.worldgen.OreGeneratorsEnd;
import tw.oresplus.worldgen.OreGeneratorsNether;
import tw.oresplus.worldgen.VillagerTradeHandler;
import tw.oresplus.worldgen.WorldGenCore;
import tw.oresplus.worldgen.WorldGenOre;
package tw.oresplus;




//import buildcraft.api.gates.ActionManager;
//import tw.oresplus.triggers.OresTrigger;
//import tw.oresplus.triggers.TriggerProvider;

@Mod(modid = References.MOD_ID, name = References.MOD_NAME, version = References.MOD_VERSION, dependencies="required-after:Forge@10.13.0.1180;after:TConstruct")
public class OresPlus {
	
	@SidedProxy(clientSide="tw.oresplus.client.ClientProxy", serverSide="tw.oresplus.core.ServerProxy") 
	public static IProxy proxy;
	
	@Instance(References.MOD_ID)
	public static OresPlus instance;

    public static OreLog log;
    
    public static ConfigMain config = new ConfigMain();
    
    public static String regenKeyOre = "DEFAULT";
    public static String regenKeyOil = "DEFAULT";
    public static String regenKeyRubberTree = "DEFAULT";
    public static String regenKeyBeehives = "DEFAULT";

    public static boolean angryPigmen = true;
    public static boolean debugMode = false;
    public static boolean difficultAlloys = false;
    public static boolean easyMineralSmelt = true;
    public static boolean iridiumPlateRecipe = true;
    public static boolean logRegenerations = false;
    
    public static WorldGenCore worldGen = new WorldGenCore();
    public static OreEventHandler eventHandler = new OreEventHandler();
    public static BucketHandler bucketHandler = new BucketHandler();
    public static TickHandler tickHandler = new TickHandler();
    public static IMCHandler imcHandler = new IMCHandler();
    public static ItemMapHelper itemMapHelper;
    
    @EventHandler
    public void preInit(FMLPreInitializationEvent event) {
    	log.init();
    	
		RecipeManager.init();

		ConfigCore.setBaseDir(event.getModConfigurationDirectory());
		config.init(event);
		
		config.load();
		
	    angryPigmen = config.getBoolean("angryPigmen", angryPigmen, "set to false to prevent zombie pigmen from attacking when mining nether ores");
	    debugMode = config.getBoolean("debugMode", debugMode, "set to true to enable finer debug logging");
	    difficultAlloys = config.getBoolean("difficultAlloys", difficultAlloys, "enable true to set brass & bronze alloy recipes to output only 2 dusts");
	    easyMineralSmelt = config.getBoolean("easyMineralSmelt", easyMineralSmelt, "disable to prevent Mineral ores smelting directly into metal");
	    iridiumPlateRecipe = config.getBoolean("iridiumPlateRecipe", iridiumPlateRecipe, "enables an ore dictionary-enabled recipe for iridium plate");
	    logRegenerations = config.getBoolean("logRegenerations", logRegenerations, "enable to log all regenerations that occur");

	    regenKeyOre = config.getString(ConfigCore.CAT_REGEN, "regenKey", regenKeyOre, "change this to regenerate ores");
	    regenKeyOil = config.getString(ConfigCore.CAT_REGEN, "regenKeyOil", regenKeyOil, "change this to regenerate buildcraft oil wells");
	    regenKeyRubberTree = config.getString(ConfigCore.CAT_REGEN, "regenKeyRubberTree", regenKeyRubberTree, "change this to regenerate IC2 rubber trees");
	    regenKeyBeehives = config.getString(ConfigCore.CAT_REGEN, "regenKeyBeehives", regenKeyBeehives, "change this to regenerate Forestry beehives");
		
		Ores.manager = new OreManager();
		
    	BlockManager.init();
    	ItemManager.init();
    	FluidManager.init();
    	GasManager.init();

    	// register aluminium->aluminum ore dictionary 
    	OreDictionary.registerOre("oreAluminum", MetallicOres.Aluminium.ore.source);
    	OreDictionary.registerOre("oreNetherAluminum", MetallicOres.Aluminium.netherOre.source);
    	OreDictionary.registerOre("blockAluminum", MetallicOres.Aluminium.block.source);
    	OreDictionary.registerOre("ingotAluminum", MetallicOres.Aluminium.ingot.source);
    	OreDictionary.registerOre("nuggetAluminum", MetallicOres.Aluminium.nugget.source);
    	OreDictionary.registerOre("crushedAluminum", MetallicOres.Aluminium.crushedOre.source);
    	OreDictionary.registerOre("crushedPurifiedAluminum", MetallicOres.Aluminium.purifiedCrushedOre.source);
    	OreDictionary.registerOre("dustAluminum", MetallicOres.Aluminium.dust.source);
    	OreDictionary.registerOre("dustTinyAluminum", MetallicOres.Aluminium.tinyDust.source);
    	OreDictionary.registerOre("clusterAluminum", MetallicOres.Aluminium.cluster.source);
    	OreDictionary.registerOre("dustDirtyAluminum", MetallicOres.Aluminium.dirtyDust.source);
    	OreDictionary.registerOre("clumpAluminum", MetallicOres.Aluminium.clump.source);
    	OreDictionary.registerOre("shardAluminum", MetallicOres.Aluminium.shard.source);
    	OreDictionary.registerOre("crystalAluminum", MetallicOres.Aluminium.crystal.source);
    	// register mercury-> quicksilver ore dictionary
    	OreDictionary.registerOre("quicksilver", Items.itemMercury.item.source);
    	
    	//Register Ore Generators
    	log.info("Registering Ore Generators");
    	for (OreGenerators oreGen : OreGenerators.values()) {
    		oreGen.registerGenerator();
    	}
    	for (OreGeneratorsNether oreGen : OreGeneratorsNether.values()) {
    		oreGen.registerGenerator();
    	}
    	for (OreGeneratorsEnd oreGen : OreGeneratorsEnd.values()) {
    		oreGen.registerGenerator();
    	}
    	
		config.save();
		
    	for (Helpers helper : Helpers.values()) {
    		helper.preInit();
    	}
    }
    
    @EventHandler
    public void init(FMLInitializationEvent event) {
    	RecipeManager.initRecipes();
    	
    	GameRegistry.registerTileEntity(TileEntityGrinder.class, "TileEntityGrinder");
    	GameRegistry.registerTileEntity(TileEntityCracker.class, "TileEntityCracker");
    	
    	MinecraftForge.EVENT_BUS.register(eventHandler);
    	MinecraftForge.EVENT_BUS.register(bucketHandler);
    	MinecraftForge.ORE_GEN_BUS.register(eventHandler);
    	FMLCommonHandler.instance().bus().register(tickHandler);
    	
    	NetworkRegistry.INSTANCE.registerGuiHandler(instance, new GuiHandler());
    	
    	itemMapHelper = new ItemMapHelper();
    	
    	//OresTrigger.registerTriggers();
    	//ActionManager.registerTriggerProvider(new TriggerProvider());
    	
    	VillagerRegistry.instance().registerVillageTradeHandler(VillagerTradeHandler.VILLAGER_BLACKSMITH, new VillagerTradeHandler(VillagerTradeHandler.VILLAGER_BLACKSMITH));

    	NetHandler.init();