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 }