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;
}
}
}