package crazypants.enderio.tool; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.world.World; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import crazypants.enderio.EnderIO; import crazypants.enderio.Log; import crazypants.enderio.api.tool.ITool; import crazypants.enderio.item.ItemYetaWrench; public class ToolUtil { public static boolean isToolEquipped(EntityPlayer player) { return getInstance().isToolEquippedImpl(player); } public static ITool getEquippedTool(EntityPlayer player) { return getInstance().getEquippedToolImpl(player); } public static ItemYetaWrench addInterfaces(ItemYetaWrench item) { return getInstance().addInterfacesImpl(item); } public static boolean breakBlockWithTool(Block block, World world, int x, int y, int z, EntityPlayer entityPlayer) { ITool tool = ToolUtil.getEquippedTool(entityPlayer); if(tool != null && entityPlayer.isSneaking() && tool.canUse(entityPlayer.getCurrentEquippedItem(), entityPlayer, x, y, z)) { if(block.removedByPlayer(world, entityPlayer, x, y, z, true)) { block.harvestBlock(world, entityPlayer, x, y, z, world.getBlockMetadata(x, y, z)); } tool.used(entityPlayer.getCurrentEquippedItem(), entityPlayer, x, y, z); return true; } return false; } private static ToolUtil instance; private static ToolUtil getInstance() { if(instance == null) { instance = new ToolUtil(); } return instance; } private final List<IToolProvider> toolProviders = new ArrayList<IToolProvider>(); private final List<IToolImpl> toolImpls = new ArrayList<IToolImpl>(); private ToolUtil() { try { Object obj = Class.forName("crazypants.enderio.tool.BuildCraftToolProvider").newInstance(); toolProviders.add((IToolProvider) obj); toolImpls.add((IToolImpl) obj); } catch (Exception e) { Log.warn("Could not find Build Craft Wrench definition. Wrench integration with other mods may fail"); } try { Object obj = Class.forName("crazypants.enderio.tool.AEToolProvider").newInstance(); toolProviders.add((IToolProvider) obj); toolImpls.add((IToolImpl) obj); } catch (Exception e) { Log.debug("Could not find AE Wrench definition. Wrench integration with AE may fail"); } toolProviders.add(new TEToolProvider()); toolImpls.add(new TEToolProvider()); } public void registerToolProvider(IToolProvider toolProvider) { toolProviders.add(toolProvider); } private boolean isToolEquippedImpl(EntityPlayer player) { return getEquippedToolImpl(player) != null; } private ITool getEquippedToolImpl(EntityPlayer player) { player = player == null ? EnderIO.proxy.getClientPlayer() : player; if(player == null) { return null; } ItemStack equipped = player.getCurrentEquippedItem(); if(equipped == null) { return null; } if(equipped.getItem() instanceof ITool) { return (ITool) equipped.getItem(); } return getToolImpl(equipped); } private ITool getToolImpl(ItemStack equipped) { for (IToolProvider provider : toolProviders) { ITool result = provider.getTool(equipped); if(result != null) { return result; } } return null; } private ItemYetaWrench addInterfacesImpl(ItemYetaWrench item) { Enhancer e = new Enhancer(); YetaWrenchProxy proxy = new YetaWrenchProxy(item, toolImpls); e.setCallback(proxy); e.setSuperclass(item.getClass()); e.setInterceptDuringConstruction(false); Class<?>[] interfaces = new Class<?>[toolImpls.size()]; int i = 0; for (IToolImpl tool : toolImpls) { interfaces[i] = tool.getInterface(); ++i; } e.setInterfaces(interfaces); ItemYetaWrench proxifiedObj = (ItemYetaWrench) e.create(); return proxifiedObj; } public static class YetaWrenchProxy implements MethodInterceptor { private ItemYetaWrench item; private Map<Class<?>, IToolImpl> impls; private YetaWrenchProxy(ItemYetaWrench item, List<IToolImpl> toolImpls) { this.item = item; impls = new HashMap<Class<?>, IToolImpl>(); for (IToolImpl tool : toolImpls) { impls.put(tool.getInterface(), tool); } } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { try { IToolImpl impl = impls.get(method.getDeclaringClass()); if(impl != null) { return impl.handleMethod(item, method, args); } method.setAccessible(true); return method.invoke(item, args); } catch (Exception e) { e.printStackTrace(); return null; } } } }