--- ../src-base/minecraft/net/minecraftforge/common/util/EnumHelper.java +++ ../src-work/minecraft/net/minecraftforge/common/util/EnumHelper.java @@ -21,7 +21,23 @@ import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.gen.structure.StructureStrongholdPieces.Stronghold.Door; import net.minecraftforge.classloading.FMLForgePlugin; +// Cauldron start +import cpw.mods.fml.relauncher.ReflectionHelper; +import net.minecraft.inventory.IInventory; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bukkit.World; +import org.bukkit.WorldType; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.inventory.InventoryType; +// Cauldron end + public class EnumHelper { private static Object reflectionFactory = null; @@ -30,6 +46,7 @@ private static Method newFieldAccessor = null; private static Method fieldAccessorSet = null; private static boolean isSetup = false; + private static final Logger logger = LogManager.getLogger(); //Some enums are decompiled with extra arguments, so lets check for that @SuppressWarnings("rawtypes") @@ -51,6 +68,73 @@ {EnumRarity.class, EnumChatFormatting.class, String.class} }; + // Cauldron start + public static Biome addBukkitBiome(String name) + { + return (Biome)addEnum(Biome.class, name, new Class[0], new Object[0]); + } + + public static World.Environment addBukkitEnvironment(int id, String name) + { + if (!isSetup) + { + setup(); + } + + return (World.Environment)addEnum(World.Environment.class, name, new Class[] { Integer.TYPE }, new Object[] { Integer.valueOf(id) }); + } + + public static WorldType addBukkitWorldType(String name) + { + if (!isSetup) + { + setup(); + } + + WorldType worldType = addEnum(WorldType.class, name, new Class [] { String.class }, new Object[] { name }); + Map BY_NAME = ReflectionHelper.getPrivateValue(WorldType.class, null, "BY_NAME"); + BY_NAME.put(name.toUpperCase(), worldType); + + return worldType; + } + + public static EntityType addBukkitEntityType(String name, Class clazz, int typeId, boolean independent) { + String entityType = name.replace("-", "_").toUpperCase(); + EntityType bukkitType = addEnum(EntityType.class, entityType, new Class[] { String.class, Class.class, Integer.TYPE, Boolean.TYPE }, new Object[] { name, clazz, typeId, independent }); + + Map NAME_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "NAME_MAP"); + Map ID_MAP = ReflectionHelper.getPrivateValue(EntityType.class, null, "ID_MAP"); + + NAME_MAP.put(name.toLowerCase(), bukkitType); + ID_MAP.put((short)typeId, bukkitType); + + + return bukkitType; + } + + public static InventoryType addInventoryType(TileEntity tileentity) + { + if (!IInventory.class.isAssignableFrom(tileentity.getClass())) return null; + String id = (String)TileEntity.classToNameMap.get(tileentity.getClass()); + + try + { + IInventory teInv = (IInventory)tileentity; + int size = teInv.getSizeInventory(); + return addEnum(org.bukkit.event.inventory.InventoryType.class, id, new Class[]{Integer.TYPE, String.class}, new Object[]{size, id}); + } + catch (Throwable e) + { + if (MinecraftServer.getServer().tileEntityConfig.enableTEInventoryWarning.getValue()) + { + logger.log(Level.WARN, "Could not create inventory type " + tileentity.getClass().getName() + " Exception: " + e.toString()); + logger.log(Level.WARN, "Could not determine default inventory size for type " + tileentity.getClass().getName() + " using size of 9"); + } + return addEnum(org.bukkit.event.inventory.InventoryType.class, id, new Class[]{Integer.TYPE, String.class}, new Object[]{9, id}); + } + } + // Cauldron end + public static EnumAction addAction(String name) { return addEnum(EnumAction.class, name); @@ -280,6 +364,86 @@ } } + // Cauldron start + @SuppressWarnings("unchecked") + public static > T replaceEnum(Class enumType, String enumName, int ordinal, Class[] paramTypes, Object[] paramValues) + { + if (!isSetup) + { + setup(); + } + + Field valuesField = null; + Field[] fields = enumType.getDeclaredFields(); + + for (Field field : fields) + { + String name = field.getName(); + if (name.equals("$VALUES") || name.equals("ENUM$VALUES")) //Added 'ENUM$VALUES' because Eclipse's internal compiler doesn't follow standards + { + valuesField = field; + break; + } + } + + int flags = (FMLForgePlugin.RUNTIME_DEOBF ? Modifier.PUBLIC : Modifier.PRIVATE) | Modifier.STATIC | Modifier.FINAL | 0x1000 /*SYNTHETIC*/; + if (valuesField == null) + { + String valueType = String.format("[L%s;", enumType.getName().replace('.', '/')); + + for (Field field : fields) + { + if ((field.getModifiers() & flags) == flags && + field.getType().getName().replace('.', '/').equals(valueType)) //Apparently some JVMs return .'s and some don't.. + { + valuesField = field; + break; + } + } + } + + if (valuesField == null) + { + FMLLog.severe("Could not find $VALUES field for enum: %s", enumType.getName()); + FMLLog.severe("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF); + FMLLog.severe("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0')); + FMLLog.severe("Fields:"); + for (Field field : fields) + { + String mods = String.format("%16s", Integer.toBinaryString(field.getModifiers())).replace(' ', '0'); + FMLLog.severe(" %s %s: %s", mods, field.getName(), field.getType().getName()); + } + return null; + } + + 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 { if (!isSetup)