@Mod( modid = "OCS", name = "OpenCCSensors", version = "1.7.5", dependencies = "required-after:ComputerCraft;after:CCTurtle;after:BuildCraft|Core;after:IC2;after:Thaumcraft;after:AppliedEnergistics;after:RailCraft;after:ArsMagica;after:UniversalElectricity;after:ThermalExpansion;after:RotaryCraft")
public class OpenCCSensors {

	public static class Blocks
	{
		public static BlockSensor sensorBlock;
		public static BlockGauge gaugeBlock;
		public static BlockBasicSensor basicSensorBlock;
	}
	
	public static class Config
	{
		public static int sensorBlockID;
		public static int basicSensorBlockID;
		public static int gaugeBlockID;
		public static int sensorCardID;
		public static int genericItemID;
		public static boolean turtlePeripheralEnabled;
		public static boolean enableAnalytics;
	}
	
	public static class Tiers {
		public static SensorTier tier1;
		public static SensorTier tier2;
		public static SensorTier tier3;
		public static SensorTier tier4;
	}
	
	public static TurtleUpgradeSensor turtleUpgradeSensor;
	

	public static class Items
	{
		public static ItemGeneric genericItem;
		public static ItemSensorCard sensorCard;
		
		public static IItemMeta rangeExtensionAntenna;
		public static IItemMeta signalAmplifier;
		public static IItemMeta advancedAmplifier;
	}

	public static int renderId;
	
	public static class Sensors {
		
		public static ProximitySensor proximitySensor;
		public static MinecartSensor minecartSensor;
		public static DroppedItemSensor droppedItemSensor;
		public static InventorySensor inventorySensor;
		public static SignSensor signSensor;
		public static SonicSensor sonicSensor;
		public static TankSensor tankSensor;
		public static WorldSensor worldSensor;
		public static MagicSensor magicSensor;
		public static MachineSensor machineSensor;
		public static PowerSensor powerSensor;
		public static CropSensor cropSensor;
	}
	
	public static String LUA_PATH;
	public static String EXTRACTED_LUA_PATH;
	
	public static LuaMount mount = new LuaMount();

	public static CreativeTabs tabOpenCCSensors = new CreativeTabs("tabOpenCCSensors") {
                public ItemStack getIconItemStack() {
                        return new ItemStack(Blocks.sensorBlock, 1, 0);
                }

				@Override
				public Item getTabIconItem() {
					return Items.sensorCard;
				}
  };

	@Instance( value = "OCS" )
	public static OpenCCSensors instance;

	@SidedProxy( clientSide = "openccsensors.client.ClientProxy", serverSide = "openccsensors.common.CommonProxy" )
	public static CommonProxy proxy;
	
	@EventHandler
	public void init( FMLInitializationEvent evt )
	{
		OCSLog.init();

		OCSLog.info( "OpenCCSensors version %s starting", FMLCommonHandler.instance().findContainerFor(instance).getVersion() );

		proxy.init();

		proxy.registerRenderInformation();
	}
	
	@EventHandler
	public void preInit( FMLPreInitializationEvent evt )
	{

		LUA_PATH = "/assets/openccsensors/lua";
		EXTRACTED_LUA_PATH = String.format("mods/OCSLua/%s/lua", FMLCommonHandler.instance().findContainerFor(OpenCCSensors.instance).getVersion());
		
		Configuration configFile = new Configuration(evt.getSuggestedConfigurationFile());

		Property prop = configFile.get("general", "turtlePeripheralEnabled", true);
		prop.comment = "Turtle Peripheral Enabled";
		Config.turtlePeripheralEnabled = prop.getBoolean(true);


		configFile.save();
		
	}
} public class BlockBasicSensor extends BlockContainer {

	public static final int PROXIMITY_SENSOR_ID = 0;

	public static class Icons {
		public static IIcon top;
		public static IIcon bottom;
		public static IIcon sideAll;
		public static IIcon sideOwner;
		public static IIcon sidePlayers;
	};

	public BlockBasicSensor() {
		super(Material.ground);
		setHardness(0.5F);
		setCreativeTab(OpenCCSensors.tabOpenCCSensors);
		GameRegistry.registerBlock(this, "basicProximitySensor");
		GameRegistry.registerTileEntity(TileEntityBasicProximitySensor.class, "basicProximitySensor");
		setBlockName("openccsensors.proximitysensor");
		
	}

	@SideOnly(Side.CLIENT)
	public void getSubBlocks(int unknown, CreativeTabs tab, List subItems) {
		subItems.add(new ItemStack(this, 1, PROXIMITY_SENSOR_ID));
	}

	@Override
	public void registerBlockIcons(IIconRegister iconRegister) {
		Icons.top = iconRegister.registerIcon("openccsensors:proxTop");
		Icons.bottom = iconRegister.registerIcon("openccsensors:proxBottom");
		Icons.sideAll = iconRegister.registerIcon("openccsensors:proxSideAll");
		Icons.sidePlayers = iconRegister.registerIcon("openccsensors:proxSidePlayers");
		Icons.sideOwner = iconRegister.registerIcon("openccsensors:proxSideOwner");
	}
	
    @Override
	public IIcon getIcon(int side, int par2)
    {
		switch(side) {
		case 0:
			return Icons.bottom;
		case 1:
			return Icons.top;
		default:
			return Icons.sideAll;
		}
    }
    
	@Override
    public IIcon getIcon(IBlockAccess blockAccess, int x, int y, int z, int side)
    {
		switch(side) {
		case 0:
			return Icons.bottom;
		case 1:
			return Icons.top;
		default:
			TileEntity tile = blockAccess.getTileEntity(x, y, z);
			if ((tile != null) && ((tile instanceof TileEntityBasicProximitySensor))) {
				switch(((TileEntityBasicProximitySensor) tile).getEntityMode()) {
					case ProximitySensor.MODE_ALL:
						return Icons.sideAll;
					case ProximitySensor.MODE_OWNER:
						return Icons.sideOwner;
					case ProximitySensor.MODE_PLAYERS:
						return Icons.sidePlayers;
				}
			}
			return Icons.sideAll;
		}
	}

	@Override
	public TileEntity createNewTileEntity(World world, int metadata) {
		return new TileEntityBasicProximitySensor();
	}

	@Override
	public boolean canProvidePower() {
		return true;
	}

	@Override
	public int isProvidingWeakPower(IBlockAccess iblockaccess, int x, int y,
			int z, int m) {
		TileEntity tile = iblockaccess.getTileEntity(x, y, z);
		if ((tile != null) && ((tile instanceof IBasicSensor))) {
			return ((IBasicSensor) tile).getPowerOutput();
		}
		return 0;
	}

	@Override
	public int isProvidingStrongPower(IBlockAccess iblockaccess, int x, int y,
			int z, int m) {
		return isProvidingWeakPower(iblockaccess, x, y, z, m);
	}

	@Override
	public void breakBlock(World worldObj, int xCoord, int yCoord, int zCoord,
			Block par5, int par6) {
		worldObj.notifyBlockOfNeighborChange(xCoord, yCoord, zCoord, OpenCCSensors.Blocks.sensorBlock);
		worldObj.notifyBlockOfNeighborChange(xCoord, yCoord - 1, zCoord, OpenCCSensors.Blocks.sensorBlock);
		worldObj.notifyBlockOfNeighborChange(xCoord, yCoord + 1, zCoord, OpenCCSensors.Blocks.sensorBlock);
		worldObj.notifyBlockOfNeighborChange(xCoord - 1, yCoord, zCoord, OpenCCSensors.Blocks.sensorBlock);
		worldObj.notifyBlockOfNeighborChange(xCoord + 1, yCoord, zCoord, OpenCCSensors.Blocks.sensorBlock);
		worldObj.notifyBlockOfNeighborChange(xCoord, yCoord, zCoord - 1, OpenCCSensors.Blocks.sensorBlock);
		worldObj.notifyBlockOfNeighborChange(xCoord, yCoord, zCoord + 1, OpenCCSensors.Blocks.sensorBlock);
		super.breakBlock(worldObj, xCoord, yCoord, zCoord, par5, par6);

	}
	
	@Override
	public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase player, ItemStack itemStack) {
		TileEntity tile = world.getTileEntity(x,  y,  z);
		if (tile != null && tile instanceof TileEntityBasicProximitySensor) {
			((TileEntityBasicProximitySensor) tile).setOwner(player.getCommandSenderName());
		}
		super.onBlockPlacedBy(world, x, y, z, player, itemStack);
	}
	
	@Override
	public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int par6, float par7, float par8, float par9) {
		if (!world.isRemote) {
			if (player.isSneaking()) {
				return false;
			}
			TileEntity tile = world.getTileEntity(x,  y,  z);
			if (tile != null && tile instanceof TileEntityBasicProximitySensor) {
				((TileEntityBasicProximitySensor) tile).onBlockClicked(player);
			}
		}
		return true;
	}

	@Override
	public boolean canBeReplacedByLeaves(IBlockAccess world, int x, int y, int z)
	{
	    return false;
	}

	@Override
    public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face)
	{
		return false;
	}

} public class BlockGauge extends BlockContainer {

	private IIcon icon;
	
	public BlockGauge() {
		super(Material.ground);
		setHardness(0.5F);
		setCreativeTab(OpenCCSensors.tabOpenCCSensors);
		GameRegistry.registerBlock(this, "gauge");
		GameRegistry.registerTileEntity(TileEntityGauge.class, "gauge");
		setBlockName("openccsensors.gauge");
	}

	@Override
	public IIcon getIcon(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    {
		return icon;
    }

	@Override
	public IIcon getIcon(int i, int damage)
	{
		return icon;
	}
	
	@Override
	public TileEntity createNewTileEntity(World world, int metadata) {
		return new TileEntityGauge();
	}
	
	@Override
	public void registerBlockIcons(IIconRegister iconRegister)
	{
		icon = iconRegister.registerIcon("openccsensors:gauge");
	}
	
	@Override
	public boolean canPlaceBlockOnSide(World world, int x, int y, int z, int side)
    {
        ForgeDirection dir = ForgeDirection.getOrientation(side);
        return (dir == NORTH && (world.isSideSolid(x, y, z + 1, NORTH) || world.getTileEntity(x, y, z + 1) != null)) ||
               (dir == SOUTH && (world.isSideSolid(x, y, z - 1, SOUTH) || world.getTileEntity(x, y, z - 1) != null)) ||
               (dir == WEST  && (world.isSideSolid(x + 1, y, z, WEST) || world.getTileEntity(x - 1, y, z) != null)) ||
               (dir == EAST  && (world.isSideSolid(x - 1, y, z, EAST) || world.getTileEntity(x - 1, y, z) != null));
    }
	
	@Override
	public boolean canPlaceBlockAt(World world, int x, int y, int z) {
		return (world.isSideSolid(x - 1, y, z, ForgeDirection.EAST) || world.getTileEntity(x - 1, y, z) != null)
				|| (world.isSideSolid(x + 1, y, z, ForgeDirection.WEST) || world.getTileEntity(x - 1, y, z) != null)
				|| (world.isSideSolid(x, y, z - 1, ForgeDirection.SOUTH) || world.getTileEntity(x, y, z - 1) != null)
				|| (world.isSideSolid(x, y, z + 1, ForgeDirection.NORTH) || world.getTileEntity(x, y, z + 1) != null);
	}
	
	@Override
	public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) {
		this.setBlockBoundsBasedOnState(world, x, y, z);
		return super.getCollisionBoundingBoxFromPool(world, x, y, z);
	}
	
	@Override
	public int getRenderType() {
		return OpenCCSensors.renderId;
	}
	
	@Override
	@SideOnly(Side.CLIENT)
	public AxisAlignedBB getSelectedBoundingBoxFromPool(World world, int x, int y, int z) {
		this.setBlockBoundsBasedOnState(world, x, y, z);
		return super.getSelectedBoundingBoxFromPool(world, x, y, z);
	}
	
	@Override
	public int onBlockPlaced(World world, int x, int y, int z,
			int side, float hitX, float hitY, float hitZ, int metadata) {
		int dir = metadata;
		
		if ((dir == 0 || side == 2) && world.blockExists(x, y, z + 1)) {
			dir = 2;
		}

		if ((dir == 0 || side == 3) && world.blockExists(x, y, z - 1)) {
			dir = 3;
		}

		if ((dir == 0 || side == 4) && world.blockExists(x + 1, y, z)) {
			dir = 4;
		}

		if ((dir == 0 || side == 5) && world.blockExists(x - 1, y, z)) {
			dir = 5;
		}
		return dir;
	}
	
	
	@Override
	public void setBlockBoundsBasedOnState(IBlockAccess blockAccess, int x, int y, int z) {
		this.updateGaugeBounds(blockAccess.getBlockMetadata(x, y, z));
	}
	
	public void updateGaugeBounds(int par1) {
		float var3 = 0.125F;

		if (par1 == 2) {
			this.setBlockBounds(0.0F, 0.0F, 1.0F - var3, 1.0F, 1.0F, 1.0F);
		}

		if (par1 == 3) {
			this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, var3);
		}

		if (par1 == 4) {
			this.setBlockBounds(1.0F - var3, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
		}

		if (par1 == 5) {
			this.setBlockBounds(0.0F, 0.0F, 0.0F, var3, 1.0F, 1.0F);
		}
	}
	
	@Override
	public boolean isOpaqueCube() {
		return false;
	}
	
	@Override
	public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) {
		return 0;
	}

	@Override
	public boolean renderAsNormalBlock() {
		return false;
	}
	
	@Override
	public void onNeighborBlockChange(World world, int x, int y, int z, Block par5) {
		int metadata = world.getBlockMetadata(x, y, z);
		ForgeDirection infront = ForgeDirection.getOrientation(metadata);
		ForgeDirection behind = infront.getOpposite();
		if (world.isAirBlock(x + behind.offsetX, y, z + behind.offsetZ)) {
			this.dropBlockAsItem(world, x, y, z, metadata, 0);
			world.setBlockToAir(x, y, z);
		}
		super.onNeighborBlockChange(world, x, y, z, par5);
	}
	
	@Override
	public boolean canBeReplacedByLeaves(IBlockAccess world, int x, int y, int z)
	{
	    return false;
	}

	@Override
    public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face)
	{
		return false;
	}
} public class BlockSensor extends BlockContainer implements IPeripheralProvider {

	public IIcon turtleIcon;
	private IIcon icon;
	
	public BlockSensor() {
		
		super(Material.ground);
		setHardness(0.5F);
		setCreativeTab(OpenCCSensors.tabOpenCCSensors);
		GameRegistry.registerBlock(this, "sensor");
		GameRegistry.registerTileEntity(TileEntitySensor.class, "sensor");
		setBlockName("openccsensors.sensor");
	}
	
	public boolean canCollideCheck(int par1, boolean par2)
    {
        return true;
    }
	
	@Override
	public TileEntity createNewTileEntity(World world, int metadata) {
		return new TileEntitySensor();
	}

	@Override
	public IIcon getIcon(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    {
		return icon;
    }

	@Override
	public IIcon getIcon(int i, int damage)
	{
		return icon;
	}

	@Override
	public void registerBlockIcons(IIconRegister iconRegister)
	{
		turtleIcon = iconRegister.registerIcon("openccsensors:turtleSensor");
		icon = iconRegister.registerIcon("openccsensors:sensor");
	}

	@Override
	public void breakBlock(World world, int x, int y, int z, Block par5, int par6) {
		MiscUtils.dropInventoryItems(world.getTileEntity(x, y, z));
		super.breakBlock(world, x, y, z, par5, par6);
	}
	
	@Override
	public int getFlammability(IBlockAccess world, int x, int y, int z, ForgeDirection face) {
		return 0;
	}
	
	@Override
	public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entity, ItemStack itemStack) {
		super.onBlockPlacedBy(world, x, y, z, entity, itemStack);
		int l = MathHelper.floor_double((double)(entity.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
		world.setBlockMetadataWithNotify(x, y, z, ForgeDirection.getOrientation(l).getOpposite().ordinal(),1);
	}
	
	@Override
	public boolean renderAsNormalBlock() {
		return false;
	}

	@Override
	public boolean isOpaqueCube() {
		return false;
	}
	
	@Override
	public int getRenderType() {
		return OpenCCSensors.renderId;
	}
	
	@Override
	public boolean onBlockActivated(World world, int x, int y, int z,
			EntityPlayer player, int side, float hitX, float hitY, float hitZ) {
		if (!world.isRemote) {
			if (player.isSneaking()) {
				return false;
			}
			player.openGui(OpenCCSensors.instance, 1987, world, x, y, z);
			return true;
		}
		return true;
	}

	@Override
	public boolean canBeReplacedByLeaves(IBlockAccess world, int x, int y, int z)
	{
	    return false;
	}
	
	@Override
    public boolean isFlammable(IBlockAccess world, int x, int y, int z, ForgeDirection face)
	{
		return false;
	}

	@Override
	public IPeripheral getPeripheral(World world, int x, int y, int z, int side) {
		TileEntity entity = world.getTileEntity(x, y, z);
		if (entity instanceof TileEntitySensor) {
			return (IPeripheral)entity;
		}
		return null;
   }
} public class ItemGeneric extends Item {

	private HashMap<Integer, IItemMeta> metaitems = new HashMap<Integer, IItemMeta>();

	public ItemGeneric() {
		super();
		setHasSubtypes(true);
		setMaxDamage(0);
		setMaxStackSize(64);
		setCreativeTab(OpenCCSensors.tabOpenCCSensors);
	}
	
	@Override
	@SideOnly(Side.CLIENT)
	public void getSubItems(Item item, CreativeTabs tab, List subItems) {
		OpenCCSensors.turtleUpgradeSensor.addTurtlesToCreative(subItems);
		for (Entry<Integer, IItemMeta> entry : metaitems.entrySet()) {
			if (entry.getValue().displayInCreative()) {
				subItems.add(new ItemStack(item, 1, entry.getKey()));
			}
		}
	}

	public void addMeta(IItemMeta meta) {
		metaitems.put(meta.getId(), meta);
	}

	public IItemMeta getMeta(ItemStack stack) {
		return getMeta(stack.getItemDamage());
	}
	
	public IItemMeta getMeta(int id) {
		return metaitems.get(id);
	}
	
	@Override
	public void registerIcons(IIconRegister iconRegister) {
		for (Entry<Integer, IItemMeta> entry : metaitems.entrySet()) {
			if (entry.getValue() instanceof IRequiresIconLoading) {
				((IRequiresIconLoading)entry.getValue()).loadIcon(iconRegister);
			}
		}
	}
	
	@Override
    public IIcon getIconFromDamage(int id)
    {
		IItemMeta meta = metaitems.get(id);
		if (meta == null) {
			return null;
		}
        return meta.getIcon();
    }

	@Override
    public String getUnlocalizedName(ItemStack itemStack)
    {
		IItemMeta meta = getMeta(itemStack);
		if  (meta == null) {
			return "";
		}
        return String.format("item.openccsensors.%s", meta.getName());
    }

} public class ItemSensorCard extends Item implements ISensorCardRegistry {

	public List<IRequiresIconLoading> iconLoadList = new ArrayList<IRequiresIconLoading>();

	public HashMap<Integer, SensorCard> cards = new HashMap<Integer, SensorCard>();

	public ItemSensorCard() {
		super();
		setMaxDamage(0);
		setHasSubtypes(true);
		setCreativeTab(OpenCCSensors.tabOpenCCSensors);
	}
	
	@Override
    public String getUnlocalizedName(ItemStack itemStack)
    {
		SensorCard card = getSensorCard(itemStack);
		if (card == null) {
			return "";
		}
        return String.format("item.openccsensors.%s", card.getSensor().getName());
    }
	
	public void registerSensors() {

		SensorTier tier1 = new SensorTier("Mk. I", EnumItemRarity.COMMON, 2, "openccsensors:tier1");
		SensorTier tier2 = new SensorTier("Mk. II", EnumItemRarity.UNCOMMON, 4, "openccsensors:tier2");
		SensorTier tier3 = new SensorTier("Mk. III", EnumItemRarity.RARE, 6, "openccsensors:tier3");
		SensorTier tier4 = new SensorTier("Mk. IV", EnumItemRarity.EPIC, 8, "openccsensors:tier4");
		
		addIconsForLoading(tier1, tier2, tier3, tier4);
		
		OpenCCSensors.Tiers.tier1 = tier1;
		OpenCCSensors.Tiers.tier2 = tier2;
		OpenCCSensors.Tiers.tier3 = tier3;
		OpenCCSensors.Tiers.tier4 = tier4;
		
		addSensorCard(1, new SensorCard(OpenCCSensors.Sensors.proximitySensor, tier1));
		addSensorCard(2, new SensorCard(OpenCCSensors.Sensors.proximitySensor, tier2));
		addSensorCard(3, new SensorCard(OpenCCSensors.Sensors.proximitySensor, tier3));
		addSensorCard(4, new SensorCard(OpenCCSensors.Sensors.proximitySensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.proximitySensor);
		
		addSensorCard(5, new SensorCard(OpenCCSensors.Sensors.droppedItemSensor, tier1));
		addSensorCard(6, new SensorCard(OpenCCSensors.Sensors.droppedItemSensor, tier2));
		addSensorCard(7, new SensorCard(OpenCCSensors.Sensors.droppedItemSensor, tier3));
		addSensorCard(8, new SensorCard(OpenCCSensors.Sensors.droppedItemSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.droppedItemSensor);
		
		/*addSensorCard(9, new SensorCard(OpenCCSensors.Sensors.signSensor, tier1));
		addSensorCard(10, new SensorCard(OpenCCSensors.Sensors.signSensor, tier2));
		addSensorCard(11, new SensorCard(OpenCCSensors.Sensors.signSensor, tier3));
		addSensorCard(12, new SensorCard(OpenCCSensors.Sensors.signSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.signSensor);
		*/
		addSensorCard(13, new SensorCard(OpenCCSensors.Sensors.minecartSensor, tier1));
		addSensorCard(14, new SensorCard(OpenCCSensors.Sensors.minecartSensor, tier2));
		addSensorCard(15, new SensorCard(OpenCCSensors.Sensors.minecartSensor, tier3));
		addSensorCard(16, new SensorCard(OpenCCSensors.Sensors.minecartSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.minecartSensor);

		addSensorCard(17, new SensorCard(OpenCCSensors.Sensors.sonicSensor, tier1));
		addSensorCard(18, new SensorCard(OpenCCSensors.Sensors.sonicSensor, tier2));
		addSensorCard(19, new SensorCard(OpenCCSensors.Sensors.sonicSensor, tier3));
		addSensorCard(20, new SensorCard(OpenCCSensors.Sensors.sonicSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.sonicSensor);

		addSensorCard(21, new SensorCard(OpenCCSensors.Sensors.tankSensor, tier1));
		addSensorCard(22, new SensorCard(OpenCCSensors.Sensors.tankSensor, tier2));
		addSensorCard(23, new SensorCard(OpenCCSensors.Sensors.tankSensor, tier3));
		addSensorCard(24, new SensorCard(OpenCCSensors.Sensors.tankSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.tankSensor);

		addSensorCard(25, new SensorCard(OpenCCSensors.Sensors.inventorySensor, tier1));
		addSensorCard(26, new SensorCard(OpenCCSensors.Sensors.inventorySensor, tier2));
		addSensorCard(27, new SensorCard(OpenCCSensors.Sensors.inventorySensor, tier3));
		addSensorCard(28, new SensorCard(OpenCCSensors.Sensors.inventorySensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.inventorySensor);

		addSensorCard(29, new SensorCard(OpenCCSensors.Sensors.worldSensor, tier1));
		addIconsForLoading(OpenCCSensors.Sensors.worldSensor);
		
		addSensorCard(30, new SensorCard(OpenCCSensors.Sensors.powerSensor, tier1));
		addSensorCard(31, new SensorCard(OpenCCSensors.Sensors.powerSensor, tier2));
		addSensorCard(32, new SensorCard(OpenCCSensors.Sensors.powerSensor, tier3));
		addSensorCard(33, new SensorCard(OpenCCSensors.Sensors.powerSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.powerSensor);
		

		addSensorCard(34, new SensorCard(OpenCCSensors.Sensors.machineSensor, tier1));
		addSensorCard(35, new SensorCard(OpenCCSensors.Sensors.machineSensor, tier2));
		addSensorCard(36, new SensorCard(OpenCCSensors.Sensors.machineSensor, tier3));
		addSensorCard(37, new SensorCard(OpenCCSensors.Sensors.machineSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.machineSensor);
		

		addSensorCard(38, new SensorCard(OpenCCSensors.Sensors.cropSensor, tier1));
		addSensorCard(39, new SensorCard(OpenCCSensors.Sensors.cropSensor, tier2));
		addSensorCard(40, new SensorCard(OpenCCSensors.Sensors.cropSensor, tier3));
		addSensorCard(41, new SensorCard(OpenCCSensors.Sensors.cropSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.cropSensor);
		
		addSensorCard(42, new SensorCard(OpenCCSensors.Sensors.magicSensor, tier1));
		addSensorCard(43, new SensorCard(OpenCCSensors.Sensors.magicSensor, tier2));
		addSensorCard(44, new SensorCard(OpenCCSensors.Sensors.magicSensor, tier3));
		addSensorCard(45, new SensorCard(OpenCCSensors.Sensors.magicSensor, tier4));
		addIconsForLoading(OpenCCSensors.Sensors.magicSensor);
		
		OCSLog.info("Added %d Sensor Cards with %d Icons", cards.size(), iconLoadList.size());
	}

	public void addIconsForLoading (IRequiresIconLoading... list){
		iconLoadList.addAll(Arrays.asList(list));
	}

	@Override
	public void registerIcons(IIconRegister iconRegister) {
		for (IRequiresIconLoading item : iconLoadList) {
			item.loadIcon(iconRegister);
		}
	}

	@SideOnly(Side.CLIENT)
	@Override
	public void addInformation(ItemStack itemStack, EntityPlayer player,
			List list, boolean par4) {
		SensorCard card = getSensorCard(itemStack);
		if (card != null) {
			ISensorTier tier = card.getTier();
			list.add(tier.getName());
		}
	}

	@SideOnly(Side.CLIENT)
	@Override
	public EnumRarity getRarity(ItemStack itemStack) {
		SensorCard card = getSensorCard(itemStack);
		if (card != null) {
			ISensorTier tier = card.getTier();
			switch (tier.getRarity()) {
			case COMMON:
				return EnumRarity.common;
			case UNCOMMON:
				return EnumRarity.uncommon;
			case RARE:
				return EnumRarity.rare;
			case EPIC:
				return EnumRarity.epic;
			}
		}
		return EnumRarity.common;
	}

	@SideOnly(Side.CLIENT)
	@Override
	public void getSubItems(Item item, CreativeTabs tab, List subItems) {
		for (Entry<Integer, SensorCard> entry : cards.entrySet()) {
			subItems.add(new ItemStack(item, 1, entry.getKey()));
		}
	}

	@SideOnly(Side.CLIENT)
	@Override
	public boolean requiresMultipleRenderPasses() {
		return true;
	}

	@SideOnly(Side.CLIENT)
	@Override
	public IIcon getIconFromDamageForRenderPass(int dmgValue, int renderPass) {
		SensorCard card = getSensorCard(dmgValue);
		return card.getIconForRenderPass(renderPass);
	}

	public SensorCard getSensorCard(ItemStack stack) {
		if (!cards.containsKey(stack.getItemDamage())) {
			stack.setItemDamage(cards.keySet().iterator().next());
		}
		SensorCard card = getSensorCard(stack.getItemDamage());
		
		return card;
	}

	public SensorCard getSensorCard(int id) {
		if (!cards.containsKey(id)) {
			return cards.values().iterator().next();
		}
		return cards.get(id);
	}
	
	public Entry<Integer, SensorCard> getEntryForSensorAndTier(ISensor sensor, SensorTier tier) {
		for (Entry<Integer, SensorCard> entry : cards.entrySet()) {
			if (entry.getValue().getSensor() == sensor && entry.getValue().getTier() == tier) {
				return entry;
			}
		}
		return null;
	}

	@Override
	public void addSensorCard(int id, SensorCard sensorCard) {
		cards.put(id, sensorCard);
		Entry<Integer, SensorCard> previousTier;
		if (sensorCard.getTier() == OpenCCSensors.Tiers.tier1){
			RecipeUtils.addTier1Recipe(
					sensorCard.getSensor().getUniqueRecipeItem(),
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, id)
			);
		}else if (sensorCard.getTier() == OpenCCSensors.Tiers.tier2){
			previousTier = getEntryForSensorAndTier(sensorCard.getSensor(), OpenCCSensors.Tiers.tier1);
			RecipeUtils.addTier2Recipe(
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, previousTier.getKey()),
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, id)
			);
		}else if (sensorCard.getTier() == OpenCCSensors.Tiers.tier3) {
			previousTier = getEntryForSensorAndTier(sensorCard.getSensor(), OpenCCSensors.Tiers.tier2);
			RecipeUtils.addTier3Recipe(
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, previousTier.getKey()),
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, id)
			);
		}else if (sensorCard.getTier() == OpenCCSensors.Tiers.tier4) {
			previousTier = getEntryForSensorAndTier(sensorCard.getSensor(), OpenCCSensors.Tiers.tier3);
			RecipeUtils.addTier4Recipe(
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, previousTier.getKey()),
					new ItemStack(OpenCCSensors.Items.sensorCard, 1, id)
			);
		}
	}
	
} public class ItemMetaRangeExtensionAntenna implements IItemMeta, IRequiresIconLoading {
	
	private int id;
	private IIcon icon;
	
	public ItemMetaRangeExtensionAntenna(int id) {
		this.id = id;
		
		OpenCCSensors.Items.genericItem.addMeta(this);
		
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
			newItemStack(1),
			new Object[] {
				" t ",
				"srs",
				"sis",
				Character.valueOf('t'), new ItemStack((Block)Block.blockRegistry.getObject("redstone_torch")),
				Character.valueOf('s'), new ItemStack((Item)Item.itemRegistry.getObject("stone")),
				Character.valueOf('r'), new ItemStack((Item)Item.itemRegistry.getObject("redstone")),
				Character.valueOf('i'), new ItemStack((Item)Item.itemRegistry.getObject("iron_ingot")),				
			}
		));
	}

	@Override
	public int getId() {
		return id;
	}

	@Override
	public boolean displayInCreative() {
		return true;
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:rangeExtensionAntenna");
	}
	
	@Override
	public ItemStack newItemStack(int size) {
		return new ItemStack(OpenCCSensors.Items.genericItem, size, getId());
	}

	@Override
	public String getName() {
		return "rangeExtensionAntenna";
	}
} public class ItemMetaSignalAmplifier implements IItemMeta, IRequiresIconLoading {

	private int id;
	private IIcon icon;
	
	public ItemMetaSignalAmplifier(int id) {
		this.id = id;

		OpenCCSensors.Items.genericItem.addMeta(this);
		
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
			newItemStack(1),
			new Object[] {
				"sgs",
				"rrr",
				"sgs",
				Character.valueOf('s'), new ItemStack((Block)Block.blockRegistry.getObject("stone")),
				Character.valueOf('r'), new ItemStack((Item)Item.itemRegistry.getObject("redstone")),
				Character.valueOf('g'), new ItemStack((Item)Item.itemRegistry.getObject("gold_ingot")),			
			}
		));
	}
	
	@Override
	public int getId() {
		return id;
	}

	@Override
	public boolean displayInCreative() {
		return true;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:signalAmplifier");
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public ItemStack newItemStack(int size) {
		return new ItemStack(OpenCCSensors.Items.genericItem, size, getId());
	}
	
	@Override
	public String getName() {
		return "signalAmplifier";
	}
} public class DroppedItemSensor implements ISensor, IRequiresIconLoading {

	private IIcon icon;
	
	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorLocation, boolean additional) {
		
		EntityItem item = (EntityItem) obj;

		HashMap response = new HashMap();
		HashMap position = new HashMap();
		
		position.put("X", item.posX - sensorLocation.posX);
		position.put("Y", item.posY - sensorLocation.posY);
		position.put("Z", item.posZ - sensorLocation.posZ);
		
		response.put("Position", position);

		ItemStack stack = item.getEntityItem();
		
		response.put("Name", InventoryUtils.getNameForItemStack(stack));
		response.put("RawName", InventoryUtils.getRawNameForStack(stack));
		
		if (additional) {
			
			response.putAll(InventoryUtils.itemstackToMap(stack));
			response.put("IsBurning", item.isBurning());
			
		}
		
		return response;
	}

	@Override
	public HashMap getTargets(World world, ChunkCoordinates location, ISensorTier tier) {
		double radius = tier.getMultiplier() * 4;
		return (HashMap) EntityUtils.getEntities(world, location, radius, EntityItem.class);
	}

	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) {
		return null;
	}

	@Override
	public String getName() {
		return "droppedItemCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:droppedItem");
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Item)Item.itemRegistry.getObject("slime_ball"));
	}

} public class MachineSensor extends TileSensor implements ISensor, IRequiresIconLoading, IGaugeSensor {

	private IIcon icon;
	
	private String[] gaugeProperties = new String[] {
		"HeatPercentage",
		"Progress"
	};
	
	@Override
	public String[] getGaugeProperties() {
		return gaugeProperties;
	}
	
	@Override
	public boolean isValidTarget(Object target) {
		return (Mods.IC2 && Ic2Utils.isValidMachineTarget(target)) ||
			   (Mods.TE && CoFHUtils.isValidMachineTarget(target)) ||
			   (Mods.RC && RotaryCraftUtils.isValidMachineTarget(target));
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:machine");
	}

	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorPos, boolean additional) {
		TileEntity tile = (TileEntity) obj;
		HashMap response = super.getDetails(tile, sensorPos);
		if (Mods.IC2) {
			response.putAll(Ic2Utils.getMachineDetails(world, obj, additional));
		}
		if (Mods.TE) {
			response.putAll(CoFHUtils.getMachineDetails(world, obj, additional));
		}
		if (Mods.RC) {
			response.putAll(RotaryCraftUtils.getMachineDetails(world, obj, additional));
		}
		return response;
	}

	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) throws Exception {
		return null;
	}

	@Override
	public String getName() {
		return "machineCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Item)Item.itemRegistry.getObject("redstone"));
	}

} public class MagicSensor extends TileSensor implements ISensor, IRequiresIconLoading {

	private IIcon icon;

	@Override
	public boolean isValidTarget(Object tile) {
		return (Mods.TC && MagicUtils.isValidAspectTarget(tile)) ||
		       (Mods.AM && MagicUtils.isValidAspectTarget(tile));
	}

	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorPos, boolean additional) {
		TileEntity tile = (TileEntity) obj;
		HashMap response = super.getDetails(tile, sensorPos);
		if (Mods.TC) {
			response.put("Aspects", MagicUtils.getMapOfAspects(world, obj, additional));
		}
		if (Mods.AM) {
			response.putAll(MagicUtils.getMapOfArsMagicaPower(world, obj, additional));
		}
		return response;
	}
	
	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) {
		return null;
	}

	@Override
	public String getName() {
		return "magicCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:magic");
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Item)Item.itemRegistry.getObject("gold_ingot"));
	}

} public class MinecartSensor implements ISensor, IRequiresIconLoading {

	private IIcon icon;


	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorPos, boolean additional) {

		EntityMinecart minecart = (EntityMinecart) obj;

		HashMap response = new HashMap();
		HashMap position = new HashMap();
		
		position.put("X", minecart.posX - sensorPos.posX);
		position.put("Y", minecart.posY - sensorPos.posY);
		position.put("Z", minecart.posZ - sensorPos.posZ);
		response.put("Position", position);
		
		response.put("Name", minecart.func_95999_t());
		response.put("RawName", EntityList.getEntityString(minecart));
		
		if (minecart instanceof IInventory) {
			response.put("Slots", InventoryUtils.invToMap((IInventory)minecart));
		}

		if (minecart instanceof IFluidHandler) {
			response.put("Tanks", TankUtils.fluidHandlerToMap((IFluidHandler)minecart));
		}
		
		if (minecart.riddenByEntity != null && minecart.riddenByEntity instanceof EntityLivingBase) {
			response.put("Riding", EntityUtils.livingToMap((EntityLivingBase)minecart.riddenByEntity, sensorPos, true));
		}
		
		if (Mods.RAIL) {
			if (minecart instanceof IEnergyTransfer) {
				response.putAll(RailcraftUtils.getEnergyDetails(minecart));
			}
			
			if (minecart instanceof IExplosiveCart) {
				response.putAll(RailcraftUtils.getExplosiveDetails(minecart));
			}
			
			if (minecart instanceof IRoutableCart) {
				response.put("RouteDestination", ((IRoutableCart)minecart).getDestination());
			}
		}
		return response;
	}

	@Override
	public HashMap getTargets(World world, ChunkCoordinates location, ISensorTier tier) {
		double radius = tier.getMultiplier() * 4;
		return (HashMap) EntityUtils.getEntities(world, location, radius, EntityMinecart.class);
	}

	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) {
		return null;
	}

	@Override
	public String getName() {
		return "minecartCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:minecart");
		
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Item)Item.itemRegistry.getObject("minecart"));
	}

} public class SignSensor extends TileSensor implements ISensor, IRequiresIconLoading {
	
	private IIcon icon;

	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorPos, boolean additional) {
		
		TileEntitySign sign = (TileEntitySign) obj;
		HashMap response = super.getDetails(sign, sensorPos);
		if (additional) {

			String signText = "";
			for (int i = 0; i < sign.signText.length; i++) {
				signText = signText + sign.signText[i];
				if (i < 3 && sign.signText[i] != "") {
					signText = signText + " ";
				}
			}
			response.put("Text", signText.trim());
		}
		
		return response;
	}
	
	@Override
	public boolean isValidTarget(Object target) {
		return target instanceof TileEntitySign;
	}

	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) {
		return null;
	}

	@Override
	public String getName() {
		return "signCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:sign");		
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Item)Item.itemRegistry.getObject("sign"));
	}

} public class SonicSensor implements ISensor, IRequiresIconLoading {
	
	private IIcon icon;
	private static final int BASE_RANGE = 1;
	
	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorPos, boolean additional) {

		Vec3 target = (Vec3) obj;

		int x = (int) target.xCoord;
		int y = (int) target.yCoord;
		int z = (int) target.zCoord;
				
		Block block = world.getBlock(x, y, z);
		
		HashMap response = new HashMap();
		
		String type = "UNKNOWN";

		if (block != null && block.getMaterial() != null) {
			if (block.getMaterial().isLiquid()) {
				type = "LIQUID";
			} else if (block.getMaterial().isSolid()) {
				type = "SOLID";
			}
		}
		
		response.put("Type", type);
		HashMap position = new HashMap();
		position.put("X", x - sensorPos.posX);
		position.put("Y", y - sensorPos.posY);
		position.put("Z", z - sensorPos.posZ);
		response.put("Position", position);
		
		return response;
	}

	@Override
	public HashMap getTargets(World world, ChunkCoordinates location, ISensorTier tier) {
		
		HashMap targets = new HashMap();

		int range = (new Double(tier.getMultiplier())).intValue() + BASE_RANGE;

		int sx = (int) location.posX;
		int sy = (int) location.posY;
		int sz = (int) location.posZ;
		
		for (int x = -range; x <= range; x++) {
			for (int y = -range; y <= range; y++) {
				for (int z = -range; z <= range; z++) {

					if (!(x == 0 && y == 0 && z == 0) && world.blockExists(sx + x, sy + y, sz + z)) {

						int bX = sx + x;
						int bY = sy + y;
						int bZ = sz + z;

						Block block = world.getBlock(bX, bY, bZ);

						if (!(world.isAirBlock(bX, bY, bZ) || block == null)) {
							Vec3 targetPos = Vec3.createVectorHelper(
									bX,
									bY,
									bZ
							);
							if ((Vec3.createVectorHelper((double)location.posX, (double)location.posY, (double)location.posZ)).distanceTo(targetPos) <= range) {
								targets.put(String.format("%s,%s,%s", x, y, z), targetPos);
							}
							
						}
					}
				}
			}
		}
		return targets;
	}

	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) {
		return null;
	}

	@Override
	public String getName() {
		return "sonicCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:sonic");
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Block)Block.blockRegistry.getObject("jukebox"));
	}

} public class TankSensor extends TileSensor implements ISensor, IRequiresIconLoading, IGaugeSensor {
	
	private IIcon icon;
	private String[] gaugeProperties = new String[] {
			"PercentFull"	
		};

	@Override
	public boolean isValidTarget(Object tile) {
		if (tile instanceof IFluidHandler) {
			FluidTankInfo[] tanks = ((IFluidHandler)tile).getTankInfo(ForgeDirection.UNKNOWN);
			if (tanks != null) {
				return tanks.length > 0;
			}
		}
		return false;
	}

	@Override
	public HashMap getDetails(World world, Object obj, ChunkCoordinates sensorPos, boolean additional) {
		TileEntity tile = (TileEntity) obj;
		HashMap response = super.getDetails(tile, sensorPos);
		response.put("Tanks", TankUtils.fluidHandlerToMap((IFluidHandler)tile));
		return response;
	}
	
	@Override
	public String[] getCustomMethods(ISensorTier tier) {
		return null;
	}

	@Override
	public Object callCustomMethod(World world, ChunkCoordinates location, int methodID,
			Object[] args, ISensorTier tier) {
		return null;
	}

	@Override
	public String getName() {
		return "tankCard";
	}

	@Override
	public IIcon getIcon() {
		return icon;
	}

	@Override
	public void loadIcon(IIconRegister iconRegistry) {
		icon = iconRegistry.registerIcon("openccsensors:tank");
	}

	@Override
	public ItemStack getUniqueRecipeItem() {
		return new ItemStack((Item)Item.itemRegistry.getObject("bucket"));
	}

	@Override
	public String[] getGaugeProperties() {
		return this.gaugeProperties;
	}

} public class TileEntityGauge extends TileEntity implements IPeripheral {
	
	
	private static ArrayList<IGaugeSensor> gaugeSensors = new ArrayList<IGaugeSensor>();
	public static void addGaugeSensor(IGaugeSensor sensor) {
		gaugeSensors.add(sensor);
	}
	public static ArrayList<IGaugeSensor> getGaugeSensors() {
		return gaugeSensors;
	}
	
	private HashMap tileProperties = new HashMap();
	private CallbackEventManager eventManager = new CallbackEventManager();
	private int percentage = 0;
	private String updatePropertyName = "";
	
	private int lastBroadcast = 1;
	
	public TileEntityGauge() {
		eventManager.registerCallback(new IMethodCallback() {

			@Override
			public String getMethodName() {
				return "getPercentage";
			}
			
			@Override
			public Object execute(IComputerAccess computer, Object[] arguments)
					throws Exception {
				return getPercentage();
			}

		});

		eventManager.registerCallback(new IMethodCallback() {

			@Override
			public String getMethodName() {
				return "setTrackedProperty";
			}
			
			@Override
			public Object execute(IComputerAccess computer, Object[] arguments)
					throws Exception {
				updatePropertyName = (String)arguments[0];
				return null;
			}

		});
	}

	@Override
	public Packet getDescriptionPacket() {
		NBTTagCompound nbt = new NBTTagCompound();
		writeToNBT(nbt);
		return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, nbt);
	}
	@Override
	public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
		readFromNBT(pkt.func_148857_g());
	}

	@Override
	public void readFromNBT(NBTTagCompound nbttagcompound) {
		this.percentage = nbttagcompound.getInteger("percentage");
		this.updatePropertyName = nbttagcompound.getString("property");
		super.readFromNBT(nbttagcompound);
	}

	@Override
	public void writeToNBT(NBTTagCompound nbttagcompound) {
		nbttagcompound.setInteger("percentage", this.percentage);
		nbttagcompound.setString("property", this.updatePropertyName);
		super.writeToNBT(nbttagcompound);
	}

	public int getFacing() {
		return (worldObj == null) ? 0 : this.getBlockMetadata();
	}
	
	public int getPercentage() {
		return percentage;
	}

	@Override
	public String getType() {
		return "gauge";
	}

	@Override
	public String[] getMethodNames() {
		return eventManager.getMethodNames();
	}

	@Override
	public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException {
		return new Object[] {
				eventManager.queueMethodCall(computer, method, arguments)
		};
	}

	@Override
	public void attach(IComputerAccess computer) {
		IMount mount = ComputerCraftAPI.createResourceMount(OpenCCSensors.class, "openccsensors", "openccsensors/mods/OCSLua/lua");
		computer.mount("ocs", mount);
	}

	@Override
	public void detach(IComputerAccess computer) {
	}

	private HashMap checkForKeys(HashMap data, String[] keys, String prefix) {
		HashMap properties = new HashMap();
		for (Object obj : data.keySet()) {
			Object value = data.get(obj);
			if (value instanceof HashMap) {
				properties.putAll(checkForKeys((HashMap)value, keys, prefix + obj.toString()));
			} else if (obj instanceof String) {
				for (String property : keys) {
					if (property.equals(obj)) {
						properties.put(prefix + property, value);
					}
				}
			}
		}
		return properties;
	}
	
	@Override
	public void updateEntity() {
		super.updateEntity();
		tileProperties.clear();
		if (this.worldObj != null && !worldObj.isRemote) {

			ForgeDirection infront = ForgeDirection.getOrientation(this.getFacing());
			ForgeDirection behind = infront.getOpposite();
			TileEntity behindTile = worldObj.getTileEntity(xCoord + behind.offsetX, yCoord, zCoord + behind.offsetZ);
			if (behindTile != null) {
				for (IGaugeSensor gaugeSensor : gaugeSensors)  {
					if (gaugeSensor.isValidTarget(behindTile)) {
						HashMap details = gaugeSensor.getDetails(worldObj, behindTile, new ChunkCoordinates(behindTile.xCoord, behindTile.yCoord, behindTile.zCoord), true);
						tileProperties.putAll(checkForKeys(details, gaugeSensor.getGaugeProperties(), ""));
					}
				}
			}
			percentage = 0;
			if (tileProperties.size() > 0) {
				if (updatePropertyName == "" || !tileProperties.containsKey(updatePropertyName)) {
					updatePropertyName = "";
					for (String property : new String[] {
							"HeatPercentage",
							"Progress",
							"StoredPercentage",
							"InventoryPercentFull"
					}) {
						if (updatePropertyName == "" && tileProperties.containsKey(property)) {
							updatePropertyName = property;
						}
					}
					if (updatePropertyName == "") {
						Entry<String, Object> entry = (Entry<String, Object>) tileProperties.entrySet().iterator().next();
						updatePropertyName = entry.getKey();
					}
				}
				percentage = ((Number) (tileProperties.get(updatePropertyName))).intValue();
			}
			if (lastBroadcast++ % 10 == 0) {
				lastBroadcast = 1;
				worldObj.markBlockForUpdate(xCoord,  yCoord,  zCoord);
			}
			eventManager.process();
		}
	}
	@Override
	public boolean equals(IPeripheral other) {
		// TODO Auto-generated method stub
		return false;
	}
} public class TurtleUpgradeSensor implements ITurtleUpgrade {

	private ArrayList<PeripheralSensor> peripheral = new ArrayList<PeripheralSensor>();
	
	public TurtleUpgradeSensor() {
	}
	
	@Override
	public IPeripheral createPeripheral(ITurtleAccess turtle,
			TurtleSide side) {
		this.peripheral.add(new PeripheralSensor(new TurtleSensorEnvironment(turtle), true));
		return this.peripheral.get(this.peripheral.size() - 1);
	}

	@Override
	public String getUnlocalisedAdjective() {
		return "turtle.openccsensors.sensor.adjective";
	}

	@Override
	public ItemStack getCraftingItem() {
		return new ItemStack(OpenCCSensors.Blocks.sensorBlock);
	}

	@Override
	public TurtleUpgradeType getType() {
		return TurtleUpgradeType.Peripheral;
	}

	@Override
	public int getUpgradeID() {
		return 180;
	}

	@Override
	public TurtleCommandResult useTool(ITurtleAccess turtle, TurtleSide side,
			TurtleVerb verb, int direction) {
		return TurtleCommandResult.failure();
	}

	@Override
	public IIcon getIcon(ITurtleAccess turtle, TurtleSide side) {
		return OpenCCSensors.Blocks.sensorBlock.turtleIcon;
	}
	
	public void addTurtlesToCreative(List subItems) {
		for (int i = 0; i <= 7; i++) {
			ItemStack turtle = GameRegistry.findItemStack("CCTurtle", "CC-TurtleExpanded", 1);
			if (turtle != null)
			{
					NBTTagCompound tag = turtle.getTagCompound();
					if (tag == null)
					{
						tag = new NBTTagCompound();
						turtle.writeToNBT(tag);
					}
					tag.setShort("leftUpgrade", (short) getUpgradeID());
					tag.setShort("rightUpgrade", (short) i);
					turtle.setTagCompound(tag);
					subItems.add(turtle);
				}
		}
	}

	@Override
	public void update(ITurtleAccess turtle, TurtleSide side) {
		if (this.peripheral != null) {
			for (PeripheralSensor peripheral : this.peripheral) {
				if (peripheral != null) {
					peripheral.update();
				}
			}		
		} 	
	}

} public class RecipeUtils {

	public static void addTier1Recipe(ItemStack input, ItemStack output) {
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
				output,
				new Object[] {
					"rpr",
					"rrr",
					"aaa",
					Character.valueOf('r'), new ItemStack((Item)Item.itemRegistry.getObject("redstone")),
					Character.valueOf('a'), new ItemStack((Item)Item.itemRegistry.getObject("paper")),
					Character.valueOf('p'), input				
				}
			));
		
	}
	
	public static void addTier2Recipe(ItemStack input, ItemStack output) {
		CraftingManager.getInstance().getRecipeList().add(new ShapelessOreRecipe(
				output,
				input,
				OpenCCSensors.Items.rangeExtensionAntenna.newItemStack(1)
			));
	}

	public static void addTier3Recipe(ItemStack input, ItemStack output) {
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
				output,
				new Object[] {
					"aca",
					" m ",
					Character.valueOf('a'), OpenCCSensors.Items.rangeExtensionAntenna.newItemStack(1),
					Character.valueOf('c'), input,
					Character.valueOf('m'), OpenCCSensors.Items.signalAmplifier.newItemStack(1)			
				}
			));
	}
	
	public static void addTier4Recipe(ItemStack input, ItemStack output) {
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
			output,
			new Object[] {
				" a ",
				"aca",
				"mpm",
				Character.valueOf('a'), OpenCCSensors.Items.rangeExtensionAntenna.newItemStack(1),
				Character.valueOf('c'), input,
				Character.valueOf('m'), OpenCCSensors.Items.signalAmplifier.newItemStack(1),	
				Character.valueOf('p'), OpenCCSensors.Items.advancedAmplifier.newItemStack(1)			
			}
		));
	}
	
	public static void addSensorRecipe() {
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
				new ItemStack(OpenCCSensors.Blocks.sensorBlock),
				new Object[] {
					"ooo",
					"ror",
					"sss",
					Character.valueOf('o'), new ItemStack((Block)Block.blockRegistry.getObject("obsidian")),
					Character.valueOf('r'), new ItemStack((Item)Item.itemRegistry.getObject("redstone")),
					Character.valueOf('s'), new ItemStack((Block)Block.blockRegistry.getObject("stone"))
				}
			));	
	}
	
	public static void addGaugeRecipe() {
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
				new ItemStack(OpenCCSensors.Blocks.gaugeBlock),
				new Object[] {
					"grm",
					Character.valueOf('g'), new ItemStack((Block)Block.blockRegistry.getObject("glass_pane")),
					Character.valueOf('r'), new ItemStack((Item)Item.itemRegistry.getObject("redstone")),
					Character.valueOf('m'), new ItemStack(getMonitor(), 1, 2)
				}
			));	
	}
	private static Block getMonitor() {
		Block monitor = null;
		try {
			Class cc = Class.forName("dan200.computercraft.ComputerCraft$Blocks");
			if (cc != null) {
				Field peripheralField = cc.getDeclaredField("peripheral");
				if (peripheralField != null) {
					monitor = (Block) peripheralField.get(cc);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return monitor;
	}
	
	public static void addProxSensorBlockRecipe() {

		Entry<Integer, SensorCard> entry = OpenCCSensors.Items.sensorCard.getEntryForSensorAndTier(
												OpenCCSensors.Sensors.proximitySensor,
												OpenCCSensors.Tiers.tier4
											);
		ItemStack proxCard = new ItemStack(OpenCCSensors.Items.sensorCard, 1, entry.getKey());
		
		CraftingManager.getInstance().getRecipeList().add(new ShapedOreRecipe(
			new ItemStack(OpenCCSensors.Blocks.basicSensorBlock),
			new Object[] {
				"   ",
				"cpc",
				"rir",
				Character.valueOf('c'), new ItemStack((Item)Item.itemRegistry.getObject("comparator")),
				Character.valueOf('p'), proxCard,
				Character.valueOf('r'), new ItemStack((Item)Item.itemRegistry.getObject("redstone")),
				Character.valueOf('i'), new ItemStack((Block)Block.blockRegistry.getObject("iron_block")),				
			}
		));
	}
}
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import net.minecraft.client.Minecraft;
import net.minecraftforge.common.ForgeVersion;
import openccsensors.OpenCCSensors;
import openccsensors.common.block.BlockBasicSensor;
import openccsensors.common.block.BlockGauge;
import openccsensors.common.block.BlockSensor;
import openccsensors.common.item.ItemGeneric;
import openccsensors.common.item.ItemSensorCard;
import openccsensors.common.item.meta.ItemMetaAdvancedAmplifier;
import openccsensors.common.item.meta.ItemMetaRangeExtensionAntenna;
import openccsensors.common.item.meta.ItemMetaSignalAmplifier;
import openccsensors.common.sensor.CropSensor;
import openccsensors.common.sensor.DroppedItemSensor;
import openccsensors.common.sensor.InventorySensor;
import openccsensors.common.sensor.MachineSensor;
import openccsensors.common.sensor.MagicSensor;
import openccsensors.common.sensor.MinecartSensor;
import openccsensors.common.sensor.PowerSensor;
import openccsensors.common.sensor.ProximitySensor;
import openccsensors.common.sensor.SignSensor;
import openccsensors.common.sensor.SonicSensor;
import openccsensors.common.sensor.TankSensor;
import openccsensors.common.sensor.WorldSensor;
import openccsensors.common.tileentity.TileEntityGauge;
import openccsensors.common.turtle.TurtleUpgradeSensor;
import openccsensors.common.util.OCSLog;
import openccsensors.common.util.RecipeUtils;
import openccsensors.common.util.ResourceExtractingUtils;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.FMLLaunchHandler;
import dan200.computercraft.api.ComputerCraftAPI;
package openccsensors.common;



public class CommonProxy {
	
	public void init() {

		initSensors();
		initBlocks();
		initItems();
		
		OpenCCSensors.turtleUpgradeSensor = new TurtleUpgradeSensor();
			
		if (OpenCCSensors.Config.turtlePeripheralEnabled) {
			ComputerCraftAPI.registerTurtleUpgrade(OpenCCSensors.turtleUpgradeSensor);
		}
		
		ComputerCraftAPI.registerPeripheralProvider(OpenCCSensors.Blocks.sensorBlock);
		
		NetworkRegistry.INSTANCE.registerGuiHandler(OpenCCSensors.instance, new GuiHandler());

		TileEntityGauge.addGaugeSensor(OpenCCSensors.Sensors.machineSensor);
		TileEntityGauge.addGaugeSensor(OpenCCSensors.Sensors.powerSensor);
		TileEntityGauge.addGaugeSensor(OpenCCSensors.Sensors.inventorySensor);
		TileEntityGauge.addGaugeSensor(OpenCCSensors.Sensors.tankSensor);
		
		RecipeUtils.addGaugeRecipe();
		RecipeUtils.addSensorRecipe();
		RecipeUtils.addProxSensorBlockRecipe();
		
		setupLuaFiles();
	}
	
	private void initSensors() {
		OpenCCSensors.Sensors.proximitySensor = new ProximitySensor();
		OpenCCSensors.Sensors.droppedItemSensor = new DroppedItemSensor();
		OpenCCSensors.Sensors.signSensor = new SignSensor();
		OpenCCSensors.Sensors.minecartSensor = new MinecartSensor();