001 package org.bukkit.event.inventory; 002 003 import org.bukkit.inventory.Inventory; 004 import org.bukkit.inventory.InventoryView; 005 import org.bukkit.entity.HumanEntity; 006 import org.bukkit.entity.Player; 007 import org.bukkit.event.HandlerList; 008 import org.bukkit.event.inventory.InventoryType.SlotType; 009 import org.bukkit.Location; 010 import org.bukkit.inventory.ItemStack; 011 import org.bukkit.scheduler.BukkitScheduler; 012 import org.bukkit.plugin.Plugin; 013 014 /** 015 * This event is called when a player clicks a slot in an inventory. 016 * <p> 017 * Because InventoryClickEvent occurs within a modification of the Inventory, 018 * not all Inventory related methods are safe to use. 019 * <p> 020 * The following should never be invoked by an EventHandler for 021 * InventoryClickEvent using the HumanEntity or InventoryView associated with 022 * this event: 023 * <ul> 024 * <li>{@link HumanEntity#closeInventory()} 025 * <li>{@link HumanEntity#openInventory(Inventory)} 026 * <li>{@link HumanEntity#openWorkbench(Location, boolean)} 027 * <li>{@link HumanEntity#openEnchanting(Location, boolean)} 028 * <li>{@link InventoryView#close()} 029 * </ul> 030 * To invoke one of these methods, schedule a task using 031 * {@link BukkitScheduler#runTask(Plugin, Runnable)}, which will run the task 032 * on the next tick. Also be aware that this is not an exhaustive list, and 033 * other methods could potentially create issues as well. 034 * <p> 035 * Assuming the EntityHuman associated with this event is an instance of a 036 * Player, manipulating the MaxStackSize or contents of an Inventory will 037 * require an Invocation of {@link Player#updateInventory()}. 038 * <p> 039 * Modifications to slots that are modified by the results of this 040 * InventoryClickEvent can be overwritten. To change these slots, this event 041 * should be cancelled and all desired changes to the inventory applied. 042 * Alternatively, scheduling a task using {@link BukkitScheduler#runTask( 043 * Plugin, Runnable)}, which would execute the task on the next tick, would 044 * work as well. 045 */ 046 public class InventoryClickEvent extends InventoryInteractEvent { 047 private static final HandlerList handlers = new HandlerList(); 048 private final ClickType click; 049 private final InventoryAction action; 050 private SlotType slot_type; 051 private int whichSlot; 052 private int rawSlot; 053 private ItemStack current = null; 054 private int hotbarKey = -1; 055 056 @Deprecated 057 public InventoryClickEvent(InventoryView view, SlotType type, int slot, boolean right, boolean shift) { 058 this(view, type, slot, right ? (shift ? ClickType.SHIFT_RIGHT : ClickType.RIGHT) : (shift ? ClickType.SHIFT_LEFT : ClickType.LEFT), InventoryAction.SWAP_WITH_CURSOR); 059 } 060 061 public InventoryClickEvent(InventoryView view, SlotType type, int slot, ClickType click, InventoryAction action) { 062 super(view); 063 this.slot_type = type; 064 this.rawSlot = slot; 065 this.whichSlot = view.convertSlot(slot); 066 this.click = click; 067 this.action = action; 068 } 069 070 public InventoryClickEvent(InventoryView view, SlotType type, int slot, ClickType click, InventoryAction action, int key) { 071 this(view, type, slot, click, action); 072 this.hotbarKey = key; 073 } 074 075 /** 076 * Gets the type of slot that was clicked. 077 * 078 * @return the slot type 079 */ 080 public SlotType getSlotType() { 081 return slot_type; 082 } 083 084 /** 085 * Gets the current ItemStack on the cursor. 086 * 087 * @return the cursor ItemStack 088 */ 089 public ItemStack getCursor() { 090 return getView().getCursor(); 091 } 092 093 /** 094 * Gets the ItemStack currently in the clicked slot. 095 * 096 * @return the item in the clicked 097 */ 098 public ItemStack getCurrentItem() { 099 if (slot_type == SlotType.OUTSIDE) { 100 return current; 101 } 102 return getView().getItem(rawSlot); 103 } 104 105 /** 106 * Gets whether or not the ClickType for this event represents a right 107 * click. 108 * 109 * @return true if the ClickType uses the right mouse button. 110 * @see ClickType#isRightClick() 111 */ 112 public boolean isRightClick() { 113 return click.isRightClick(); 114 } 115 116 /** 117 * Gets whether or not the ClickType for this event represents a left 118 * click. 119 * 120 * @return true if the ClickType uses the left mouse button. 121 * @see ClickType#isLeftClick() 122 */ 123 public boolean isLeftClick() { 124 return click.isLeftClick(); 125 } 126 127 /** 128 * Gets whether the ClickType for this event indicates that the key was 129 * pressed down when the click was made. 130 * 131 * @return true if the ClickType uses Shift or Ctrl. 132 * @see ClickType#isShiftClick() 133 */ 134 public boolean isShiftClick() { 135 return click.isShiftClick(); 136 } 137 138 /** 139 * Sets the item on the cursor. 140 * 141 * @param stack the new cursor item 142 * @deprecated This changes the ItemStack in their hand before any 143 * calculations are applied to the Inventory, which has a tendency to 144 * create inconsistencies between the Player and the server, and to 145 * make unexpected changes in the behavior of the clicked Inventory. 146 */ 147 @Deprecated 148 public void setCursor(ItemStack stack) { 149 getView().setCursor(stack); 150 } 151 152 /** 153 * Sets the ItemStack currently in the clicked slot. 154 * 155 * @param stack the item to be placed in the current slot 156 */ 157 public void setCurrentItem(ItemStack stack) { 158 if (slot_type == SlotType.OUTSIDE) { 159 current = stack; 160 } else { 161 getView().setItem(rawSlot, stack); 162 } 163 } 164 165 /** 166 * The slot number that was clicked, ready for passing to 167 * {@link Inventory#getItem(int)}. Note that there may be two slots with 168 * the same slot number, since a view links two different inventories. 169 * 170 * @return The slot number. 171 */ 172 public int getSlot() { 173 return whichSlot; 174 } 175 176 /** 177 * The raw slot number clicked, ready for passing to {@link InventoryView 178 * #getItem(int)} This slot number is unique for the view. 179 * 180 * @return the slot number 181 */ 182 public int getRawSlot() { 183 return rawSlot; 184 } 185 186 /** 187 * If the ClickType is NUMBER_KEY, this method will return the index of 188 * the pressed key (0-8). 189 * 190 * @return the number on the key minus 1 (range 0-8); or -1 if not 191 * a NUMBER_KEY action 192 */ 193 public int getHotbarButton() { 194 return hotbarKey; 195 } 196 197 /** 198 * Gets the InventoryAction that triggered this event. 199 * <p> 200 * This action cannot be changed, and represents what the normal outcome 201 * of the event will be. To change the behavior of this 202 * InventoryClickEvent, changes must be manually applied. 203 * 204 * @return the InventoryAction that triggered this event. 205 */ 206 public InventoryAction getAction() { 207 return action; 208 } 209 210 /** 211 * Gets the ClickType for this event. 212 * <p> 213 * This is insulated against changes to the inventory by other plugins. 214 * 215 * @return the type of inventory click 216 */ 217 public ClickType getClick() { 218 return click; 219 } 220 221 @Override 222 public HandlerList getHandlers() { 223 return handlers; 224 } 225 226 public static HandlerList getHandlerList() { 227 return handlers; 228 } 229 }