Newer
Older
ultramine_bukkit / src / main / java / org / bukkit / Material.java
@vlad20012 vlad20012 on 24 Feb 2017 30 KB initial
package org.bukkit;

import com.google.common.collect.Maps;
import net.minecraftforge.cauldron.api.inventory.BukkitOreDictionary;
import net.minecraftforge.cauldron.api.inventory.OreDictionaryEntry;
import net.minecraftforge.common.util.EnumHelper;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.ItemStack;
import org.bukkit.map.MapView;
import org.bukkit.material.Bed;
import org.bukkit.material.Button;
import org.bukkit.material.Cake;
import org.bukkit.material.Cauldron;
import org.bukkit.material.Chest;
import org.bukkit.material.Coal;
import org.bukkit.material.CocoaPlant;
import org.bukkit.material.Command;
import org.bukkit.material.Crops;
import org.bukkit.material.DetectorRail;
import org.bukkit.material.Diode;
import org.bukkit.material.Dispenser;
import org.bukkit.material.Door;
import org.bukkit.material.Dye;
import org.bukkit.material.EnderChest;
import org.bukkit.material.FlowerPot;
import org.bukkit.material.Furnace;
import org.bukkit.material.Gate;
import org.bukkit.material.Ladder;
import org.bukkit.material.Lever;
import org.bukkit.material.LongGrass;
import org.bukkit.material.MaterialData;
import org.bukkit.material.MonsterEggs;
import org.bukkit.material.Mushroom;
import org.bukkit.material.NetherWarts;
import org.bukkit.material.PistonBaseMaterial;
import org.bukkit.material.PistonExtensionMaterial;
import org.bukkit.material.PoweredRail;
import org.bukkit.material.PressurePlate;
import org.bukkit.material.Pumpkin;
import org.bukkit.material.Rails;
import org.bukkit.material.RedstoneTorch;
import org.bukkit.material.RedstoneWire;
import org.bukkit.material.Sandstone;
import org.bukkit.material.Sign;
import org.bukkit.material.Skull;
import org.bukkit.material.SmoothBrick;
import org.bukkit.material.SpawnEgg;
import org.bukkit.material.Stairs;
import org.bukkit.material.Step;
import org.bukkit.material.Torch;
import org.bukkit.material.TrapDoor;
import org.bukkit.material.Tree;
import org.bukkit.material.Tripwire;
import org.bukkit.material.TripwireHook;
import org.bukkit.material.Vine;
import org.bukkit.material.WoodenStep;
import org.bukkit.material.Wool;
import org.bukkit.potion.Potion;
import org.bukkit.util.Java15Compat;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

// Cauldron start
// Cauldron end

/**
 * An enum of all material IDs accepted by the official server and client
 */
public enum Material
{
	AIR(0, 0),
	STONE(1),
	GRASS(2),
	DIRT(3),
	COBBLESTONE(4),
	WOOD(5, Tree.class),
	SAPLING(6, Tree.class),
	BEDROCK(7),
	WATER(8, MaterialData.class),
	STATIONARY_WATER(9, MaterialData.class),
	LAVA(10, MaterialData.class),
	STATIONARY_LAVA(11, MaterialData.class),
	SAND(12),
	GRAVEL(13),
	GOLD_ORE(14),
	IRON_ORE(15),
	COAL_ORE(16),
	LOG(17, Tree.class),
	LEAVES(18, Tree.class),
	SPONGE(19),
	GLASS(20),
	LAPIS_ORE(21),
	LAPIS_BLOCK(22),
	DISPENSER(23, Dispenser.class),
	SANDSTONE(24, Sandstone.class),
	NOTE_BLOCK(25),
	BED_BLOCK(26, Bed.class),
	POWERED_RAIL(27, PoweredRail.class),
	DETECTOR_RAIL(28, DetectorRail.class),
	PISTON_STICKY_BASE(29, PistonBaseMaterial.class),
	WEB(30),
	LONG_GRASS(31, LongGrass.class),
	DEAD_BUSH(32),
	PISTON_BASE(33, PistonBaseMaterial.class),
	PISTON_EXTENSION(34, PistonExtensionMaterial.class),
	WOOL(35, Wool.class),
	PISTON_MOVING_PIECE(36),
	YELLOW_FLOWER(37),
	RED_ROSE(38),
	BROWN_MUSHROOM(39),
	RED_MUSHROOM(40),
	GOLD_BLOCK(41),
	IRON_BLOCK(42),
	DOUBLE_STEP(43, Step.class),
	STEP(44, Step.class),
	BRICK(45),
	TNT(46),
	BOOKSHELF(47),
	MOSSY_COBBLESTONE(48),
	OBSIDIAN(49),
	TORCH(50, Torch.class),
	FIRE(51),
	MOB_SPAWNER(52),
	WOOD_STAIRS(53, Stairs.class),
	CHEST(54, Chest.class),
	REDSTONE_WIRE(55, RedstoneWire.class),
	DIAMOND_ORE(56),
	DIAMOND_BLOCK(57),
	WORKBENCH(58),
	CROPS(59, Crops.class),
	SOIL(60, MaterialData.class),
	FURNACE(61, Furnace.class),
	BURNING_FURNACE(62, Furnace.class),
	SIGN_POST(63, 64, Sign.class),
	WOODEN_DOOR(64, Door.class),
	LADDER(65, Ladder.class),
	RAILS(66, Rails.class),
	COBBLESTONE_STAIRS(67, Stairs.class),
	WALL_SIGN(68, 64, Sign.class),
	LEVER(69, Lever.class),
	STONE_PLATE(70, PressurePlate.class),
	IRON_DOOR_BLOCK(71, Door.class),
	WOOD_PLATE(72, PressurePlate.class),
	REDSTONE_ORE(73),
	GLOWING_REDSTONE_ORE(74),
	REDSTONE_TORCH_OFF(75, RedstoneTorch.class),
	REDSTONE_TORCH_ON(76, RedstoneTorch.class),
	STONE_BUTTON(77, Button.class),
	SNOW(78),
	ICE(79),
	SNOW_BLOCK(80),
	CACTUS(81, MaterialData.class),
	CLAY(82),
	SUGAR_CANE_BLOCK(83, MaterialData.class),
	JUKEBOX(84),
	FENCE(85),
	PUMPKIN(86, Pumpkin.class),
	NETHERRACK(87),
	SOUL_SAND(88),
	GLOWSTONE(89),
	PORTAL(90),
	JACK_O_LANTERN(91, Pumpkin.class),
	CAKE_BLOCK(92, 64, Cake.class),
	DIODE_BLOCK_OFF(93, Diode.class),
	DIODE_BLOCK_ON(94, Diode.class),
	@Deprecated
	LOCKED_CHEST(95),
	STAINED_GLASS(95),
	TRAP_DOOR(96, TrapDoor.class),
	MONSTER_EGGS(97, MonsterEggs.class),
	SMOOTH_BRICK(98, SmoothBrick.class),
	HUGE_MUSHROOM_1(99, Mushroom.class),
	HUGE_MUSHROOM_2(100, Mushroom.class),
	IRON_FENCE(101),
	THIN_GLASS(102),
	MELON_BLOCK(103),
	PUMPKIN_STEM(104, MaterialData.class),
	MELON_STEM(105, MaterialData.class),
	VINE(106, Vine.class),
	FENCE_GATE(107, Gate.class),
	BRICK_STAIRS(108, Stairs.class),
	SMOOTH_STAIRS(109, Stairs.class),
	MYCEL(110),
	WATER_LILY(111),
	NETHER_BRICK(112),
	NETHER_FENCE(113),
	NETHER_BRICK_STAIRS(114, Stairs.class),
	NETHER_WARTS(115, NetherWarts.class),
	ENCHANTMENT_TABLE(116),
	BREWING_STAND(117, MaterialData.class),
	CAULDRON(118, Cauldron.class),
	ENDER_PORTAL(119),
	ENDER_PORTAL_FRAME(120),
	ENDER_STONE(121),
	DRAGON_EGG(122),
	REDSTONE_LAMP_OFF(123),
	REDSTONE_LAMP_ON(124),
	WOOD_DOUBLE_STEP(125, WoodenStep.class),
	WOOD_STEP(126, WoodenStep.class),
	COCOA(127, CocoaPlant.class),
	SANDSTONE_STAIRS(128, Stairs.class),
	EMERALD_ORE(129),
	ENDER_CHEST(130, EnderChest.class),
	TRIPWIRE_HOOK(131, TripwireHook.class),
	TRIPWIRE(132, Tripwire.class),
	EMERALD_BLOCK(133),
	SPRUCE_WOOD_STAIRS(134, Stairs.class),
	BIRCH_WOOD_STAIRS(135, Stairs.class),
	JUNGLE_WOOD_STAIRS(136, Stairs.class),
	COMMAND(137, Command.class),
	BEACON(138),
	COBBLE_WALL(139),
	FLOWER_POT(140, FlowerPot.class),
	CARROT(141),
	POTATO(142),
	WOOD_BUTTON(143, Button.class),
	SKULL(144, Skull.class),
	ANVIL(145),
	TRAPPED_CHEST(146),
	GOLD_PLATE(147),
	IRON_PLATE(148),
	REDSTONE_COMPARATOR_OFF(149),
	REDSTONE_COMPARATOR_ON(150),
	DAYLIGHT_DETECTOR(151),
	REDSTONE_BLOCK(152),
	QUARTZ_ORE(153),
	HOPPER(154),
	QUARTZ_BLOCK(155),
	QUARTZ_STAIRS(156, Stairs.class),
	ACTIVATOR_RAIL(157, PoweredRail.class),
	DROPPER(158, Dispenser.class),
	STAINED_CLAY(159),
	STAINED_GLASS_PANE(160),
	LEAVES_2(161),
	LOG_2(162),
	ACACIA_STAIRS(163, Stairs.class),
	DARK_OAK_STAIRS(164, Stairs.class),
	HAY_BLOCK(170),
	CARPET(171),
	HARD_CLAY(172),
	COAL_BLOCK(173),
	PACKED_ICE(174),
	DOUBLE_PLANT(175),
	// ----- Item Separator -----
	IRON_SPADE(256, 1, 250),
	IRON_PICKAXE(257, 1, 250),
	IRON_AXE(258, 1, 250),
	FLINT_AND_STEEL(259, 1, 64),
	APPLE(260),
	BOW(261, 1, 384),
	ARROW(262),
	COAL(263, Coal.class),
	DIAMOND(264),
	IRON_INGOT(265),
	GOLD_INGOT(266),
	IRON_SWORD(267, 1, 250),
	WOOD_SWORD(268, 1, 59),
	WOOD_SPADE(269, 1, 59),
	WOOD_PICKAXE(270, 1, 59),
	WOOD_AXE(271, 1, 59),
	STONE_SWORD(272, 1, 131),
	STONE_SPADE(273, 1, 131),
	STONE_PICKAXE(274, 1, 131),
	STONE_AXE(275, 1, 131),
	DIAMOND_SWORD(276, 1, 1561),
	DIAMOND_SPADE(277, 1, 1561),
	DIAMOND_PICKAXE(278, 1, 1561),
	DIAMOND_AXE(279, 1, 1561),
	STICK(280),
	BOWL(281),
	MUSHROOM_SOUP(282, 1),
	GOLD_SWORD(283, 1, 32),
	GOLD_SPADE(284, 1, 32),
	GOLD_PICKAXE(285, 1, 32),
	GOLD_AXE(286, 1, 32),
	STRING(287),
	FEATHER(288),
	SULPHUR(289),
	WOOD_HOE(290, 1, 59),
	STONE_HOE(291, 1, 131),
	IRON_HOE(292, 1, 250),
	DIAMOND_HOE(293, 1, 1561),
	GOLD_HOE(294, 1, 32),
	SEEDS(295),
	WHEAT(296),
	BREAD(297),
	LEATHER_HELMET(298, 1, 55),
	LEATHER_CHESTPLATE(299, 1, 80),
	LEATHER_LEGGINGS(300, 1, 75),
	LEATHER_BOOTS(301, 1, 65),
	CHAINMAIL_HELMET(302, 1, 165),
	CHAINMAIL_CHESTPLATE(303, 1, 240),
	CHAINMAIL_LEGGINGS(304, 1, 225),
	CHAINMAIL_BOOTS(305, 1, 195),
	IRON_HELMET(306, 1, 165),
	IRON_CHESTPLATE(307, 1, 240),
	IRON_LEGGINGS(308, 1, 225),
	IRON_BOOTS(309, 1, 195),
	DIAMOND_HELMET(310, 1, 363),
	DIAMOND_CHESTPLATE(311, 1, 528),
	DIAMOND_LEGGINGS(312, 1, 495),
	DIAMOND_BOOTS(313, 1, 429),
	GOLD_HELMET(314, 1, 77),
	GOLD_CHESTPLATE(315, 1, 112),
	GOLD_LEGGINGS(316, 1, 105),
	GOLD_BOOTS(317, 1, 91),
	FLINT(318),
	PORK(319),
	GRILLED_PORK(320),
	PAINTING(321),
	GOLDEN_APPLE(322),
	SIGN(323, 16),
	WOOD_DOOR(324, 1),
	BUCKET(325, 16),
	WATER_BUCKET(326, 1),
	LAVA_BUCKET(327, 1),
	MINECART(328, 1),
	SADDLE(329, 1),
	IRON_DOOR(330, 1),
	REDSTONE(331),
	SNOW_BALL(332, 16),
	BOAT(333, 1),
	LEATHER(334),
	MILK_BUCKET(335, 1),
	CLAY_BRICK(336),
	CLAY_BALL(337),
	SUGAR_CANE(338),
	PAPER(339),
	BOOK(340),
	SLIME_BALL(341),
	STORAGE_MINECART(342, 1),
	POWERED_MINECART(343, 1),
	EGG(344, 16),
	COMPASS(345),
	FISHING_ROD(346, 1, 64),
	WATCH(347),
	GLOWSTONE_DUST(348),
	RAW_FISH(349),
	COOKED_FISH(350),
	INK_SACK(351, Dye.class),
	BONE(352),
	SUGAR(353),
	CAKE(354, 1),
	BED(355, 1),
	DIODE(356),
	COOKIE(357),
	/**
	 * @see MapView
	 */
	MAP(358, MaterialData.class),
	SHEARS(359, 1, 238),
	MELON(360),
	PUMPKIN_SEEDS(361),
	MELON_SEEDS(362),
	RAW_BEEF(363),
	COOKED_BEEF(364),
	RAW_CHICKEN(365),
	COOKED_CHICKEN(366),
	ROTTEN_FLESH(367),
	ENDER_PEARL(368, 16),
	BLAZE_ROD(369),
	GHAST_TEAR(370),
	GOLD_NUGGET(371),
	NETHER_STALK(372),
	/**
	 * @see Potion
	 */
	POTION(373, 1, MaterialData.class),
	GLASS_BOTTLE(374),
	SPIDER_EYE(375),
	FERMENTED_SPIDER_EYE(376),
	BLAZE_POWDER(377),
	MAGMA_CREAM(378),
	BREWING_STAND_ITEM(379),
	CAULDRON_ITEM(380),
	EYE_OF_ENDER(381),
	SPECKLED_MELON(382),
	MONSTER_EGG(383, 64, SpawnEgg.class),
	EXP_BOTTLE(384, 64),
	FIREBALL(385, 64),
	BOOK_AND_QUILL(386, 1),
	WRITTEN_BOOK(387, 16),
	EMERALD(388, 64),
	ITEM_FRAME(389),
	FLOWER_POT_ITEM(390),
	CARROT_ITEM(391),
	POTATO_ITEM(392),
	BAKED_POTATO(393),
	POISONOUS_POTATO(394),
	EMPTY_MAP(395),
	GOLDEN_CARROT(396),
	SKULL_ITEM(397),
	CARROT_STICK(398, 1, 25),
	NETHER_STAR(399),
	PUMPKIN_PIE(400),
	FIREWORK(401),
	FIREWORK_CHARGE(402),
	ENCHANTED_BOOK(403, 1),
	REDSTONE_COMPARATOR(404),
	NETHER_BRICK_ITEM(405),
	QUARTZ(406),
	EXPLOSIVE_MINECART(407, 1),
	HOPPER_MINECART(408, 1),
	IRON_BARDING(417, 1),
	GOLD_BARDING(418, 1),
	DIAMOND_BARDING(419, 1),
	LEASH(420),
	NAME_TAG(421),
	COMMAND_MINECART(422, 1),
	GOLD_RECORD(2256, 1),
	GREEN_RECORD(2257, 1),
	RECORD_3(2258, 1),
	RECORD_4(2259, 1),
	RECORD_5(2260, 1),
	RECORD_6(2261, 1),
	RECORD_7(2262, 1),
	RECORD_8(2263, 1),
	RECORD_9(2264, 1),
	RECORD_10(2265, 1),
	RECORD_11(2266, 1),
	RECORD_12(2267, 1),;

	private final int id;
	private final Constructor<? extends MaterialData> ctor;
	private static Material[] byId = new Material[383];
	private static Map<String, Material> BY_NAME = Maps.newHashMap(); // Cauldron - remove final
	private final int maxStack;
	private final short durability;
	// Cauldron start
	private static Object reflectionFactory;
	private static Method newConstructorAccessor;
	private static Method newInstance;
	private static Method newFieldAccessor;
	private static Method fieldAccessorSet;
	private static boolean isSetup;
	private boolean isForgeBlock = false;
	// Cauldron end

	private Material(final int id)
	{
		this(id, 64);
	}

	// Cauldron start - constructor used to set if the Material is a block or not
	private Material(final int id, boolean flag)
	{
		this(id, 64);
		this.isForgeBlock = flag;
	}
	// Cauldron end

	private Material(final int id, final int stack)
	{
		this(id, stack, MaterialData.class);
	}

	private Material(final int id, final int stack, final int durability)
	{
		this(id, stack, durability, MaterialData.class);
	}

	private Material(final int id, final Class<? extends MaterialData> data)
	{
		this(id, 64, data);
	}

	private Material(final int id, final int stack, final Class<? extends MaterialData> data)
	{
		this(id, stack, 0, data);
	}

	private Material(final int id, final int stack, final int durability, final Class<? extends MaterialData> data)
	{
		this.id = id;
		this.durability = (short) durability;
		this.maxStack = stack;
		// try to cache the constructor for this material
		try
		{
			this.ctor = data.getConstructor(int.class, byte.class);
		} catch(NoSuchMethodException ex)
		{
			throw new AssertionError(ex);
		} catch(SecurityException ex)
		{
			throw new AssertionError(ex);
		}
	}

	/**
	 * Gets the item ID or block ID of this Material
	 *
	 * @return ID of this material
	 * @deprecated Magic value
	 */
	@Deprecated
	public int getId()
	{
		return id;
	}

	/**
	 * Gets the maximum amount of this material that can be held in a stack
	 *
	 * @return Maximum stack size for this material
	 */
	public int getMaxStackSize()
	{
		return maxStack;
	}

	/**
	 * Gets the maximum durability of this material
	 *
	 * @return Maximum durability for this material
	 */
	public short getMaxDurability()
	{
		return durability;
	}

	/**
	 * Gets the MaterialData class associated with this Material
	 *
	 * @return MaterialData associated with this Material
	 */
	public Class<? extends MaterialData> getData()
	{
		return ctor.getDeclaringClass();
	}

	/**
	 * Constructs a new MaterialData relevant for this Material, with the
	 * given initial data
	 *
	 * @param raw Initial data to construct the MaterialData with
	 * @return New MaterialData with the given data
	 * @deprecated Magic value
	 */
	@Deprecated
	public MaterialData getNewData(final byte raw)
	{
		try
		{
			return ctor.newInstance(id, raw);
		} catch(InstantiationException ex)
		{
			final Throwable t = ex.getCause();
			if(t instanceof RuntimeException)
			{
				throw (RuntimeException) t;
			}
			if(t instanceof Error)
			{
				throw (Error) t;
			}
			throw new AssertionError(t);
		} catch(Throwable t)
		{
			throw new AssertionError(t);
		}
	}

	/**
	 * Checks if this Material is a placable block
	 *
	 * @return true if this material is a block
	 */
	public boolean isBlock()
	{
		return id < 256 || isForgeBlock; // Cauldron
	}

	/**
	 * Checks if this Material is edible.
	 *
	 * @return true if this Material is edible.
	 */
	public boolean isEdible()
	{
		switch(this)
		{
		case BREAD:
		case CARROT_ITEM:
		case BAKED_POTATO:
		case POTATO_ITEM:
		case POISONOUS_POTATO:
		case GOLDEN_CARROT:
		case PUMPKIN_PIE:
		case COOKIE:
		case MELON:
		case MUSHROOM_SOUP:
		case RAW_CHICKEN:
		case COOKED_CHICKEN:
		case RAW_BEEF:
		case COOKED_BEEF:
		case RAW_FISH:
		case COOKED_FISH:
		case PORK:
		case GRILLED_PORK:
		case APPLE:
		case GOLDEN_APPLE:
		case ROTTEN_FLESH:
		case SPIDER_EYE:
			return true;
		default:
			return false;
		}
	}

	/**
	 * Attempts to get the Material with the given ID
	 *
	 * @param id ID of the material to get
	 * @return Material if found, or null
	 * @deprecated Magic value
	 */
	@Deprecated
	public static Material getMaterial(final int id)
	{
		if(byId.length > id && id >= 0)
		{
			return byId[id];
		}
		else
		{
			return null;
		}
	}

	/**
	 * Attempts to get the Material with the given name.
	 * <p>
	 * This is a normal lookup, names must be the precise name they are given
	 * in the enum.
	 *
	 * @param name Name of the material to get
	 * @return Material if found, or null
	 */
	public static Material getMaterial(final String name)
	{
		return BY_NAME.get(name);
	}

	/**
	 * Attempts to match the Material with the given name.
	 * <p>
	 * This is a match lookup; names will be converted to uppercase, then
	 * stripped of special characters in an attempt to format it like the
	 * enum.
	 * <p>
	 * Using this for match by ID is deprecated.
	 *
	 * @param name Name of the material to get
	 * @return Material if found, or null
	 */
	public static Material matchMaterial(final String name)
	{
		Validate.notNull(name, "Name cannot be null");

		Material result = null;

		try
		{
			result = getMaterial(Integer.parseInt(name));
		} catch(NumberFormatException ex)
		{
		}

		if(result == null)
		{
			// Cauldron start - extract to normalizeName()
			String filtered = normalizeName(name);
			result = BY_NAME.get(filtered);
			// Cauldron end
		}

		// Cauldron start - Try the ore dictionary
		if(result == null)
		{
			BukkitOreDictionary dict = net.minecraftforge.cauldron.api.Cauldron.getOreDictionary();
			OreDictionaryEntry entry = dict.getOreEntry(name);
			if(entry != null)
			{
				List<ItemStack> items = dict.getDefinitions(entry);
				if(items.size() > 0)
				{
					// TODO check sanity on multiple item results
					ItemStack item = items.get(0);
					if(item.getDurability() == 0 || item.getDurability() == Short.MAX_VALUE)
					{
						result = item.getType();
					}
					else
					{
						// bad! we have an item with data!
					}
				}
			}
		}
		// Cauldron end

		return result;
	}

    /* ===============================  Cauldron START ============================= */

	// use a normalize() function to ensure it is accessible after a round-trip
	public static String normalizeName(String name)
	{
		return name.toUpperCase().replaceAll("(:|\\s)", "_").replaceAll("\\W", "");
	}

	public static Material addMaterial(int id, boolean isBlock)
	{
		return addMaterial(id, "X" + String.valueOf(id), isBlock);
	}

	public static Material addMaterial(int id, String name, boolean isBlock)
	{
		if(byId[id] == null)
		{
			String materialName = normalizeName(name);
			Material material = (Material) EnumHelper.addEnum(Material.class, materialName, new Class[]{Integer.TYPE, Boolean.TYPE}, new Object[]{Integer.valueOf(id), isBlock});
			byId[id] = material;
			BY_NAME.put(materialName, material);
			BY_NAME.put("X" + String.valueOf(id), material);
			return material;
		}
		return null;
	}

	public static void setMaterialName(int id, String name, boolean flag)
	{
		String materialName = normalizeName(name);

		if(byId[id] == null)
		{
			addMaterial(id, materialName, flag);
		}
		else // replace existing enum
		{
		  /* TODO: find out how to do this with Forge's EnumHelper (addEnum?) - used for enabling descriptive (vs numeric) Material names
          Material material = getMaterial(id);
          BY_NAME.remove(material);
          Material newMaterial = EnumHelper.replaceEnum(Material.class, material_name, material.ordinal(), new Class[] { Integer.TYPE }, new Object[] { Integer.valueOf(id) });
          if (newMaterial == null)
              System.out.println("Error replacing Material " + name + " with id " + id);
          else {
              byId[id] = newMaterial;
              BY_NAME.put(material_name, newMaterial);
          }
          */
		}
	}

	private static void setup()
	{
		if(isSetup)
		{
			return;
		}
		try
		{
			Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory", new Class[0]);
			reflectionFactory = getReflectionFactory.invoke(null, new Object[0]);
			newConstructorAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newConstructorAccessor", new Class[]{Constructor.class});
			newInstance = Class.forName("sun.reflect.ConstructorAccessor").getDeclaredMethod("newInstance", new Class[]{Object[].class});
			newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", new Class[]{Field.class, Boolean.TYPE});
			fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", new Class[]{Object.class, Object.class});
		} catch(Exception e)
		{
			e.printStackTrace();
		}

		isSetup = true;
	}

	private static Object getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes) throws Exception
	{
		Class[] parameterTypes = null;

		parameterTypes = new Class[additionalParameterTypes.length + 2];
		parameterTypes[0] = String.class;
		parameterTypes[1] = Integer.TYPE;
		System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);

		return newConstructorAccessor.invoke(reflectionFactory, new Object[]{enumClass.getDeclaredConstructor(parameterTypes)});
	}

	private static <T extends Enum<?>> T makeEnum(Class<T> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues) throws Exception
	{
		Object[] parms = null;

		parms = new Object[additionalValues.length + 2];
		parms[0] = value;
		parms[1] = Integer.valueOf(ordinal);
		System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);

		return (T) enumClass.cast(newInstance.invoke(getConstructorAccessor(enumClass, additionalTypes), new Object[]{parms}));
	}

	private static void setFailsafeFieldValue(Field field, Object target, Object value) throws Exception
	{
		field.setAccessible(true);
		Field modifiersField = Field.class.getDeclaredField("modifiers");
		modifiersField.setAccessible(true);
		modifiersField.setInt(field, field.getModifiers() & 0xFFFFFFEF);
		Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, new Object[]{field, Boolean.valueOf(false)});
		fieldAccessorSet.invoke(fieldAccessor, new Object[]{target, value});
	}

	private static void blankField(Class<?> enumClass, String fieldName) throws Exception
	{
		for(Field field : Class.class.getDeclaredFields())
			if(field.getName().contains(fieldName))
			{
				field.setAccessible(true);
				setFailsafeFieldValue(field, enumClass, null);
				break;
			}
	}

	private static void cleanEnumCache(Class<?> enumClass) throws Exception
	{
		blankField(enumClass, "enumConstantDirectory");
		blankField(enumClass, "enumConstants");
	}

	public static <T extends Enum<?>> T replaceEnum(Class<T> enumType, String enumName, int ordinal, Class<?>[] paramTypes, Object[] paramValues)
	{
		if(!isSetup) setup();
		Field valuesField = null;
		Field[] fields = enumType.getDeclaredFields();
		int flags = 4122;
		String valueType = String.format("[L%s;", new Object[]{enumType.getName()});

		for(Field field : fields)
		{
			if(((field.getModifiers() & flags) != flags) || (!field.getType().getName().equals(valueType)))
			{
				continue;
			}
			valuesField = field;
			break;
		}

		valuesField.setAccessible(true);
		try
		{
			Enum[] previousValues = (Enum[]) (Enum[]) valuesField.get(enumType);
			Enum[] newValues = new Enum[previousValues.length];
			Enum newValue = null;
			for(Enum enumValue : previousValues)
			{
				if(enumValue.ordinal() == ordinal)
				{
					newValue = makeEnum(enumType, enumName, ordinal, paramTypes, paramValues);
					newValues[enumValue.ordinal()] = newValue;
				}
				else newValues[enumValue.ordinal()] = enumValue;
			}
			List values = new ArrayList(Arrays.asList(newValues));

			setFailsafeFieldValue(valuesField, null, values.toArray((Enum[]) (Enum[]) Array.newInstance(enumType, 0)));
			cleanEnumCache(enumType);
			return (T) newValue;
		} catch(Exception e)
		{
			e.printStackTrace();
			throw new RuntimeException(e.getMessage(), e);
		}
	}
    /* ===============================  Cauldron END============================= */

	static
	{
		// Cauldron start
		byId = new Material[32000];
		BY_NAME = Maps.newHashMap();

		reflectionFactory = null;
		newConstructorAccessor = null;
		newInstance = null;
		newFieldAccessor = null;
		fieldAccessorSet = null;
		isSetup = false;
		// Cauldron end
		for(Material material : values())
		{
			if(byId.length > material.id)
			{
				byId[material.id] = material;
			}
			else
			{
				byId = Java15Compat.Arrays_copyOfRange(byId, 0, material.id + 2);
				byId[material.id] = material;
			}
			BY_NAME.put(material.name(), material);
		}
	}

	/**
	 * @return True if this material represents a playable music disk.
	 */
	public boolean isRecord()
	{
		return id >= GOLD_RECORD.id && id <= RECORD_12.id;
	}

	/**
	 * Check if the material is a block and solid (cannot be passed through by
	 * a player)
	 *
	 * @return True if this material is a block and solid
	 */
	public boolean isSolid()
	{
		if(!isBlock() || id == 0)
		{
			return false;
		}
		switch(this)
		{
		case STONE:
		case GRASS:
		case DIRT:
		case COBBLESTONE:
		case WOOD:
		case BEDROCK:
		case SAND:
		case GRAVEL:
		case GOLD_ORE:
		case IRON_ORE:
		case COAL_ORE:
		case LOG:
		case LEAVES:
		case SPONGE:
		case GLASS:
		case LAPIS_ORE:
		case LAPIS_BLOCK:
		case DISPENSER:
		case SANDSTONE:
		case NOTE_BLOCK:
		case BED_BLOCK:
		case PISTON_STICKY_BASE:
		case PISTON_BASE:
		case PISTON_EXTENSION:
		case WOOL:
		case PISTON_MOVING_PIECE:
		case GOLD_BLOCK:
		case IRON_BLOCK:
		case DOUBLE_STEP:
		case STEP:
		case BRICK:
		case TNT:
		case BOOKSHELF:
		case MOSSY_COBBLESTONE:
		case OBSIDIAN:
		case MOB_SPAWNER:
		case WOOD_STAIRS:
		case CHEST:
		case DIAMOND_ORE:
		case DIAMOND_BLOCK:
		case WORKBENCH:
		case SOIL:
		case FURNACE:
		case BURNING_FURNACE:
		case SIGN_POST:
		case WOODEN_DOOR:
		case COBBLESTONE_STAIRS:
		case WALL_SIGN:
		case STONE_PLATE:
		case IRON_DOOR_BLOCK:
		case WOOD_PLATE:
		case REDSTONE_ORE:
		case GLOWING_REDSTONE_ORE:
		case ICE:
		case SNOW_BLOCK:
		case CACTUS:
		case CLAY:
		case JUKEBOX:
		case FENCE:
		case PUMPKIN:
		case NETHERRACK:
		case SOUL_SAND:
		case GLOWSTONE:
		case JACK_O_LANTERN:
		case CAKE_BLOCK:
		case LOCKED_CHEST:
		case STAINED_GLASS:
		case TRAP_DOOR:
		case MONSTER_EGGS:
		case SMOOTH_BRICK:
		case HUGE_MUSHROOM_1:
		case HUGE_MUSHROOM_2:
		case IRON_FENCE:
		case THIN_GLASS:
		case MELON_BLOCK:
		case FENCE_GATE:
		case BRICK_STAIRS:
		case SMOOTH_STAIRS:
		case MYCEL:
		case NETHER_BRICK:
		case NETHER_FENCE:
		case NETHER_BRICK_STAIRS:
		case ENCHANTMENT_TABLE:
		case BREWING_STAND:
		case CAULDRON:
		case ENDER_PORTAL_FRAME:
		case ENDER_STONE:
		case DRAGON_EGG:
		case REDSTONE_LAMP_OFF:
		case REDSTONE_LAMP_ON:
		case WOOD_DOUBLE_STEP:
		case WOOD_STEP:
		case SANDSTONE_STAIRS:
		case EMERALD_ORE:
		case ENDER_CHEST:
		case EMERALD_BLOCK:
		case SPRUCE_WOOD_STAIRS:
		case BIRCH_WOOD_STAIRS:
		case JUNGLE_WOOD_STAIRS:
		case COMMAND:
		case BEACON:
		case COBBLE_WALL:
		case ANVIL:
		case TRAPPED_CHEST:
		case GOLD_PLATE:
		case IRON_PLATE:
		case DAYLIGHT_DETECTOR:
		case REDSTONE_BLOCK:
		case QUARTZ_ORE:
		case HOPPER:
		case QUARTZ_BLOCK:
		case QUARTZ_STAIRS:
		case DROPPER:
		case STAINED_CLAY:
		case HAY_BLOCK:
		case HARD_CLAY:
		case COAL_BLOCK:
		case STAINED_GLASS_PANE:
		case LEAVES_2:
		case LOG_2:
		case ACACIA_STAIRS:
		case DARK_OAK_STAIRS:
		case PACKED_ICE:
			return true;
		default:
			return false;
		}
	}

	/**
	 * Check if the material is a block and does not block any light
	 *
	 * @return True if this material is a block and does not block any light
	 */
	public boolean isTransparent()
	{
		if(!isBlock())
		{
			return false;
		}
		switch(this)
		{
		case AIR:
		case SAPLING:
		case POWERED_RAIL:
		case DETECTOR_RAIL:
		case LONG_GRASS:
		case DEAD_BUSH:
		case YELLOW_FLOWER:
		case RED_ROSE:
		case BROWN_MUSHROOM:
		case RED_MUSHROOM:
		case TORCH:
		case FIRE:
		case REDSTONE_WIRE:
		case CROPS:
		case LADDER:
		case RAILS:
		case LEVER:
		case REDSTONE_TORCH_OFF:
		case REDSTONE_TORCH_ON:
		case STONE_BUTTON:
		case SNOW:
		case SUGAR_CANE_BLOCK:
		case PORTAL:
		case DIODE_BLOCK_OFF:
		case DIODE_BLOCK_ON:
		case PUMPKIN_STEM:
		case MELON_STEM:
		case VINE:
		case WATER_LILY:
		case NETHER_WARTS:
		case ENDER_PORTAL:
		case COCOA:
		case TRIPWIRE_HOOK:
		case TRIPWIRE:
		case FLOWER_POT:
		case CARROT:
		case POTATO:
		case WOOD_BUTTON:
		case SKULL:
		case REDSTONE_COMPARATOR_OFF:
		case REDSTONE_COMPARATOR_ON:
		case ACTIVATOR_RAIL:
		case CARPET:
		case DOUBLE_PLANT:
			return true;
		default:
			return false;
		}
	}

	/**
	 * Check if the material is a block and can catch fire
	 *
	 * @return True if this material is a block and can catch fire
	 */
	public boolean isFlammable()
	{
		if(!isBlock())
		{
			return false;
		}
		switch(this)
		{
		case WOOD:
		case LOG:
		case LEAVES:
		case NOTE_BLOCK:
		case BED_BLOCK:
		case LONG_GRASS:
		case DEAD_BUSH:
		case WOOL:
		case TNT:
		case BOOKSHELF:
		case WOOD_STAIRS:
		case CHEST:
		case WORKBENCH:
		case SIGN_POST:
		case WOODEN_DOOR:
		case WALL_SIGN:
		case WOOD_PLATE:
		case JUKEBOX:
		case FENCE:
		case TRAP_DOOR:
		case HUGE_MUSHROOM_1:
		case HUGE_MUSHROOM_2:
		case VINE:
		case FENCE_GATE:
		case WOOD_DOUBLE_STEP:
		case WOOD_STEP:
		case SPRUCE_WOOD_STAIRS:
		case BIRCH_WOOD_STAIRS:
		case JUNGLE_WOOD_STAIRS:
		case TRAPPED_CHEST:
		case DAYLIGHT_DETECTOR:
		case CARPET:
		case LEAVES_2:
		case LOG_2:
		case ACACIA_STAIRS:
		case DARK_OAK_STAIRS:
			return true;
		default:
			return false;
		}
	}

	/**
	 * Check if the material is a block and can burn away
	 *
	 * @return True if this material is a block and can burn away
	 */
	public boolean isBurnable()
	{
		if(!isBlock())
		{
			return false;
		}
		switch(this)
		{
		case WOOD:
		case LOG:
		case LEAVES:
		case LONG_GRASS:
		case WOOL:
		case YELLOW_FLOWER:
		case RED_ROSE:
		case TNT:
		case BOOKSHELF:
		case WOOD_STAIRS:
		case FENCE:
		case VINE:
		case WOOD_DOUBLE_STEP:
		case WOOD_STEP:
		case SPRUCE_WOOD_STAIRS:
		case BIRCH_WOOD_STAIRS:
		case JUNGLE_WOOD_STAIRS:
		case HAY_BLOCK:
		case COAL_BLOCK:
		case LEAVES_2:
		case LOG_2:
		case CARPET:
		case DOUBLE_PLANT:
			return true;
		default:
			return false;
		}
	}

	/**
	 * Check if the material is a block and completely blocks vision
	 *
	 * @return True if this material is a block and completely blocks vision
	 */
	public boolean isOccluding()
	{
		if(!isBlock())
		{
			return false;
		}
		switch(this)
		{
		case STONE:
		case GRASS:
		case DIRT:
		case COBBLESTONE:
		case WOOD:
		case BEDROCK:
		case SAND:
		case GRAVEL:
		case GOLD_ORE:
		case IRON_ORE:
		case COAL_ORE:
		case LOG:
		case SPONGE:
		case LAPIS_ORE:
		case LAPIS_BLOCK:
		case DISPENSER:
		case SANDSTONE:
		case NOTE_BLOCK:
		case WOOL:
		case GOLD_BLOCK:
		case IRON_BLOCK:
		case DOUBLE_STEP:
		case BRICK:
		case BOOKSHELF:
		case MOSSY_COBBLESTONE:
		case OBSIDIAN:
		case MOB_SPAWNER:
		case DIAMOND_ORE:
		case DIAMOND_BLOCK:
		case WORKBENCH:
		case FURNACE:
		case BURNING_FURNACE:
		case REDSTONE_ORE:
		case GLOWING_REDSTONE_ORE:
		case SNOW_BLOCK:
		case CLAY:
		case JUKEBOX:
		case PUMPKIN:
		case NETHERRACK:
		case SOUL_SAND:
		case JACK_O_LANTERN:
		case MONSTER_EGGS:
		case SMOOTH_BRICK:
		case HUGE_MUSHROOM_1:
		case HUGE_MUSHROOM_2:
		case MELON_BLOCK:
		case MYCEL:
		case NETHER_BRICK:
		case ENDER_PORTAL_FRAME:
		case ENDER_STONE:
		case REDSTONE_LAMP_OFF:
		case REDSTONE_LAMP_ON:
		case WOOD_DOUBLE_STEP:
		case EMERALD_ORE:
		case EMERALD_BLOCK:
		case COMMAND:
		case QUARTZ_ORE:
		case QUARTZ_BLOCK:
		case DROPPER:
		case STAINED_CLAY:
		case HAY_BLOCK:
		case HARD_CLAY:
		case COAL_BLOCK:
		case LOG_2:
		case PACKED_ICE:
			return true;
		default:
			return false;
		}
	}

	/**
	 * @return True if this material is affected by gravity.
	 */
	public boolean hasGravity()
	{
		if(!isBlock())
		{
			return false;
		}
		switch(this)
		{
		case SAND:
		case GRAVEL:
		case ANVIL:
			return true;
		default:
			return false;
		}
	}
}