@Override
 public boolean execute(Plugin plugin, CommandSender sender, String[] args) {
   notFromConsole(sender);
   Player player = (Player) sender;
   MessagePager pager = MessagePager.getPager(sender).clear();
   pager.add(STBUtil.dumpItemStack(player.getItemInHand()));
   pager.showPage();
   return true;
 }
 @Override
 public void onInteractItem(PlayerInteractEvent event) {
   final Player player = event.getPlayer();
   if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
     Block b = event.getClickedBlock();
     if (STBUtil.isCrop(b.getType())) {
       b = b.getRelative(BlockFace.DOWN);
     }
     final List<Location> l = new ArrayList<Location>();
     for (int i = -getRadius(); i <= getRadius(); i++) {
       for (int j = -getRadius(); j <= getRadius(); j++) {
         Block b1 = b.getRelative(i, 0, j);
         if (b1.getType() == Material.SOIL) {
           l.add(b1.getLocation());
         }
       }
     }
     if (!l.isEmpty()) {
       Bukkit.getScheduler()
           .runTask(
               getProviderPlugin(),
               new Runnable() {
                 @SuppressWarnings("deprecation")
                 @Override
                 public void run() {
                   for (Location loc : l) {
                     player.sendBlockChange(loc, Material.WOOL, getSaturationData(loc.getBlock()));
                   }
                 }
               });
       Bukkit.getScheduler()
           .runTaskLater(
               getProviderPlugin(),
               new Runnable() {
                 @SuppressWarnings("deprecation")
                 @Override
                 public void run() {
                   for (Location loc : l) {
                     player.sendBlockChange(
                         loc, loc.getBlock().getType(), loc.getBlock().getData());
                   }
                 }
               },
               30L);
       event.setCancelled(true);
     }
   }
 }
 @Override
 public void onClicked(InventoryClickEvent event) {
   int newValue = value;
   if (event.isLeftClick()) {
     newValue -= event.isShiftClick() ? altIncr : incr;
   } else if (event.isRightClick()) {
     newValue += event.isShiftClick() ? altIncr : incr;
   }
   newValue = Math.max(Math.min(newValue, range.getMaximumInteger()), range.getMinimumInteger());
   if (newValue != value && callback.run(newValue)) {
     value = newValue;
     event.setCurrentItem(getTexture());
   } else {
     // vetoed by the block!
     if (event.getWhoClicked() instanceof Player) {
       STBUtil.complain((Player) event.getWhoClicked());
     }
   }
 }
 @EventHandler(ignoreCancelled = true)
 public void onFurnaceInsert(final InventoryClickEvent event) {
   if (event.getInventory().getType() != InventoryType.FURNACE) {
     return;
   }
   if (event.getRawSlot() == 0 && event.getCursor().getType() != Material.AIR) {
     if (!validateSmeltingIngredient(event.getCursor())) {
       event.setCancelled(true);
     }
   } else if (event.getRawSlot() >= event.getView().getTopInventory().getSize()) {
     if (event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY) {
       if (!validateSmeltingIngredient(event.getCurrentItem())
           && !STBUtil.isFuel(event.getCurrentItem().getType())) {
         event.setCancelled(true);
         int newSlot = findNewSlot(event);
         if (newSlot >= 0) {
           event.getWhoClicked().getInventory().setItem(newSlot, event.getCurrentItem());
           event.setCurrentItem(null);
         }
       }
     }
   } else if (event.getRawSlot() == 2
       && SensibleToolbox.getItemRegistry().isSTBItem(event.getCurrentItem())) {
     // work around CB bug where shift-clicking custom items out of furnace seems
     // to cause a de-sync, leaving phantom items in the furnace
     Bukkit.getScheduler()
         .runTask(
             plugin,
             new Runnable() {
               @Override
               public void run() {
                 STBUtil.forceInventoryRefresh(event.getInventory());
               }
             });
   }
 }
public class HyperStorageUnit extends BigStorageUnit {
  private static final MaterialData md = STBUtil.makeLog(TreeSpecies.ACACIA);

  public HyperStorageUnit() {
    super();
  }

  public HyperStorageUnit(ConfigurationSection conf) {
    super(conf);
  }

  @Override
  public MaterialData getMaterialData() {
    return md;
  }

  @Override
  public String getItemName() {
    return "HSU";
  }

  @Override
  public Recipe getRecipe() {
    IntegratedCircuit ic = new IntegratedCircuit();
    BigStorageUnit bsu = new BigStorageUnit();
    registerCustomIngredients(ic, bsu);
    ShapedRecipe recipe = new ShapedRecipe(toItemStack());
    recipe.shape("OIO", "EBE", "RGR");
    recipe.setIngredient('O', Material.OBSIDIAN);
    recipe.setIngredient('I', ic.getMaterialData());
    recipe.setIngredient('E', Material.ENDER_PEARL);
    recipe.setIngredient('B', bsu.getMaterialData());
    recipe.setIngredient('R', Material.REDSTONE);
    recipe.setIngredient('G', Material.GOLD_INGOT);
    return recipe;
  }

  @Override
  public Recipe[] getExtraRecipes() {
    return new Recipe[0];
  }

  @Override
  public String getCraftingNotes() {
    return null;
  }

  @Override
  public int getMaxCharge() {
    return 1000;
  }

  @Override
  public int getChargeRate() {
    return 10;
  }

  @Override
  public int getChargeMeterSlot() {
    return 35;
  }

  public int getStackCapacity() {
    return 33554431; // 2^31 items for a 64-item stack
  }

  public int getEnergyCellSlot() {
    return 36;
  }

  public int getChargeDirectionSlot() {
    return 37;
  }

  @Override
  public int getInventoryGUISize() {
    return 45;
  }

  @Override
  public boolean acceptsEnergy(BlockFace face) {
    return true;
  }

  @Override
  protected boolean dropsItemsOnBreak() {
    return false;
  }

  @Override
  public String[] getLore() {
    return new String[] {
      "Hyper Storage Unit",
      "Stores up to " + getStackCapacity() + " stacks",
      "of a single item type",
      "Keeps storage when broken",
      "Needs power to function"
    };
  }

  @Override
  public String[] getExtraLore() {
    if (getTotalAmount() > 0) {
      String[] l = super.getExtraLore();
      String[] l2 = Arrays.copyOf(l, l.length + 1);
      l2[l2.length - 1] =
          ChatColor.WHITE
              + "Stored: "
              + ChatColor.YELLOW
              + getTotalAmount()
              + " "
              + ItemNames.lookup(getStoredItemType());
      return l2;
    } else {
      return super.getExtraLore();
    }
  }

  @Override
  public double getChargePerOperation(int nItems) {
    return 0.05 * nItems;
  }

  @Override
  public void onBlockUnregistered(Location loc) {
    // move all output items into storage so they don't get dropped
    ItemStack output = getOutputItem();
    if (output != null) {
      setStorageAmount(getStorageAmount() + output.getAmount());
      setOutputAmount(0);
      setOutputItem(null);
    }
    super.onBlockUnregistered(loc);
  }
}