Commits
Miles Holder authored and md_5 committed 2b4b6d14241
1 1 | package org.bukkit.inventory; |
2 2 | |
3 - | import com.google.common.base.Preconditions; |
4 3 | import org.bukkit.entity.HumanEntity; |
5 4 | import org.bukkit.event.inventory.InventoryType; |
6 5 | import org.jetbrains.annotations.NotNull; |
7 6 | import org.jetbrains.annotations.Nullable; |
8 7 | |
9 8 | /** |
10 9 | * Represents a view linking two inventories and a single player (whose |
11 10 | * inventory may or may not be one of the two). |
12 11 | * <p> |
13 12 | * Note: If you implement this interface but fail to satisfy the expected |
14 13 | * contracts of certain methods, there's no guarantee that the game will work |
15 14 | * as it should. |
16 15 | */ |
17 - | public abstract class InventoryView { |
16 + | public interface InventoryView { |
18 17 | public static final int OUTSIDE = -999; |
19 18 | /** |
20 19 | * Represents various extra properties of certain inventory windows. |
21 20 | */ |
22 21 | public enum Property { |
23 22 | /** |
24 23 | * The progress of the down-pointing arrow in a brewing inventory. |
25 24 | */ |
26 25 | BREW_TIME(0, InventoryType.BREWING), |
27 26 | /** |
132 131 | public int getId() { |
133 132 | return id; |
134 133 | } |
135 134 | } |
136 135 | /** |
137 136 | * Get the upper inventory involved in this transaction. |
138 137 | * |
139 138 | * @return the inventory |
140 139 | */ |
141 140 | |
142 - | public abstract Inventory getTopInventory(); |
141 + | public Inventory getTopInventory(); |
143 142 | |
144 143 | /** |
145 144 | * Get the lower inventory involved in this transaction. |
146 145 | * |
147 146 | * @return the inventory |
148 147 | */ |
149 148 | |
150 - | public abstract Inventory getBottomInventory(); |
149 + | public Inventory getBottomInventory(); |
151 150 | |
152 151 | /** |
153 152 | * Get the player viewing. |
154 153 | * |
155 154 | * @return the player |
156 155 | */ |
157 156 | |
158 - | public abstract HumanEntity getPlayer(); |
157 + | public HumanEntity getPlayer(); |
159 158 | |
160 159 | /** |
161 160 | * Determine the type of inventory involved in the transaction. This |
162 161 | * indicates the window style being shown. It will never return PLAYER, |
163 162 | * since that is common to all windows. |
164 163 | * |
165 164 | * @return the inventory type |
166 165 | */ |
167 166 | |
168 - | public abstract InventoryType getType(); |
167 + | public InventoryType getType(); |
169 168 | |
170 169 | /** |
171 170 | * Sets one item in this inventory view by its raw slot ID. |
172 171 | * <p> |
173 172 | * Note: If slot ID -999 is chosen, it may be expected that the item is |
174 173 | * dropped on the ground. This is not required behaviour, however. |
175 174 | * |
176 175 | * @param slot The ID as returned by InventoryClickEvent.getRawSlot() |
177 176 | * @param item The new item to put in the slot, or null to clear it. |
178 177 | */ |
179 - | public void setItem(int slot, ItemStack item) { |
180 - | Inventory inventory = getInventory(slot); |
181 - | if (inventory != null) { |
182 - | inventory.setItem(convertSlot(slot), item); |
183 - | } else if (item != null) { |
184 - | getPlayer().getWorld().dropItemNaturally(getPlayer().getLocation(), item); |
185 - | } |
186 - | } |
178 + | public void setItem(int slot, ItemStack item); |
187 179 | |
188 180 | /** |
189 181 | * Gets one item in this inventory view by its raw slot ID. |
190 182 | * |
191 183 | * @param slot The ID as returned by InventoryClickEvent.getRawSlot() |
192 184 | * @return The item currently in the slot. |
193 185 | */ |
194 186 | |
195 - | public ItemStack getItem(int slot) { |
196 - | Inventory inventory = getInventory(slot); |
197 - | return (inventory == null) ? null : inventory.getItem(convertSlot(slot)); |
198 - | } |
187 + | public ItemStack getItem(int slot); |
199 188 | |
200 189 | /** |
201 190 | * Sets the item on the cursor of one of the viewing players. |
202 191 | * |
203 192 | * @param item The item to put on the cursor, or null to remove the item |
204 193 | * on their cursor. |
205 194 | */ |
206 - | public final void setCursor( ItemStack item) { |
207 - | getPlayer().setItemOnCursor(item); |
208 - | } |
195 + | public void setCursor( ItemStack item); |
209 196 | |
210 197 | /** |
211 198 | * Get the item on the cursor of one of the viewing players. |
212 199 | * |
213 200 | * @return The item on the player's cursor, or null if they aren't holding |
214 201 | * one. |
215 202 | */ |
216 203 | |
217 - | public final ItemStack getCursor() { |
218 - | return getPlayer().getItemOnCursor(); |
219 - | } |
204 + | public ItemStack getCursor(); |
220 205 | |
221 206 | /** |
222 207 | * Gets the inventory corresponding to the given raw slot ID. |
223 208 | * |
224 209 | * If the slot ID is {@link #OUTSIDE} null will be returned, otherwise |
225 210 | * behaviour for illegal and negative slot IDs is undefined. |
226 211 | * |
227 212 | * May be used with {@link #convertSlot(int)} to directly index an |
228 213 | * underlying inventory. |
229 214 | * |
230 215 | * @param rawSlot The raw slot ID. |
231 216 | * @return corresponding inventory, or null |
232 217 | */ |
233 218 | |
234 - | public final Inventory getInventory(int rawSlot) { |
235 - | // Slot may be -1 if not properly detected due to client bug |
236 - | // e.g. dropping an item into part of the enchantment list section of an enchanting table |
237 - | if (rawSlot == OUTSIDE || rawSlot == -1) { |
238 - | return null; |
239 - | } |
240 - | Preconditions.checkArgument(rawSlot >= 0, "Negative, non outside slot %s", rawSlot); |
241 - | Preconditions.checkArgument(rawSlot < countSlots(), "Slot %s greater than inventory slot count", rawSlot); |
242 - | |
243 - | if (rawSlot < getTopInventory().getSize()) { |
244 - | return getTopInventory(); |
245 - | } else { |
246 - | return getBottomInventory(); |
247 - | } |
248 - | } |
219 + | public Inventory getInventory(int rawSlot); |
249 220 | |
250 221 | /** |
251 222 | * Converts a raw slot ID into its local slot ID into whichever of the two |
252 223 | * inventories the slot points to. |
253 224 | * <p> |
254 225 | * If the raw slot refers to the upper inventory, it will be returned |
255 226 | * unchanged and thus be suitable for getTopInventory().getItem(); if it |
256 227 | * refers to the lower inventory, the output will differ from the input |
257 228 | * and be suitable for getBottomInventory().getItem(). |
258 229 | * |
259 230 | * @param rawSlot The raw slot ID. |
260 231 | * @return The converted slot ID. |
261 232 | */ |
262 - | public final int convertSlot(int rawSlot) { |
263 - | int numInTop = getTopInventory().getSize(); |
264 - | // Index from the top inventory as having slots from [0,size] |
265 - | if (rawSlot < numInTop) { |
266 - | return rawSlot; |
267 - | } |
268 - | |
269 - | // Move down the slot index by the top size |
270 - | int slot = rawSlot - numInTop; |
271 - | |
272 - | // Player crafting slots are indexed differently. The matrix is caught by the first return. |
273 - | // Creative mode is the same, except that you can't see the crafting slots (but the IDs are still used) |
274 - | if (getType() == InventoryType.CRAFTING || getType() == InventoryType.CREATIVE) { |
275 - | /* |
276 - | * Raw Slots: |
277 - | * |
278 - | * 5 1 2 0 |
279 - | * 6 3 4 |
280 - | * 7 |
281 - | * 8 45 |
282 - | * 9 10 11 12 13 14 15 16 17 |
283 - | * 18 19 20 21 22 23 24 25 26 |
284 - | * 27 28 29 30 31 32 33 34 35 |
285 - | * 36 37 38 39 40 41 42 43 44 |
286 - | */ |
287 - | |
288 - | /* |
289 - | * Converted Slots: |
290 - | * |
291 - | * 39 1 2 0 |
292 - | * 38 3 4 |
293 - | * 37 |
294 - | * 36 40 |
295 - | * 9 10 11 12 13 14 15 16 17 |
296 - | * 18 19 20 21 22 23 24 25 26 |
297 - | * 27 28 29 30 31 32 33 34 35 |
298 - | * 0 1 2 3 4 5 6 7 8 |
299 - | */ |
300 - | |
301 - | if (slot < 4) { |
302 - | // Send [5,8] to [39,36] |
303 - | return 39 - slot; |
304 - | } else if (slot > 39) { |
305 - | // Slot lives in the extra slot section |
306 - | return slot; |
307 - | } else { |
308 - | // Reset index so 9 -> 0 |
309 - | slot -= 4; |
310 - | } |
311 - | } |
312 - | |
313 - | // 27 = 36 - 9 |
314 - | if (slot >= 27) { |
315 - | // Put into hotbar section |
316 - | slot -= 27; |
317 - | } else { |
318 - | // Take out of hotbar section |
319 - | // 9 = 36 - 27 |
320 - | slot += 9; |
321 - | } |
322 - | |
323 - | return slot; |
324 - | } |
233 + | public int convertSlot(int rawSlot); |
325 234 | |
326 235 | /** |
327 236 | * Determine the type of the slot by its raw slot ID. |
328 237 | * <p> |
329 238 | * If the type of the slot is unknown, then |
330 239 | * {@link InventoryType.SlotType#CONTAINER} will be returned. |
331 240 | * |
332 241 | * @param slot The raw slot ID |
333 242 | * @return the slot type |
334 243 | */ |
335 244 | |
336 - | public final InventoryType.SlotType getSlotType(int slot) { |
337 - | InventoryType.SlotType type = InventoryType.SlotType.CONTAINER; |
338 - | if (slot >= 0 && slot < this.getTopInventory().getSize()) { |
339 - | switch (this.getType()) { |
340 - | case BLAST_FURNACE: |
341 - | case FURNACE: |
342 - | case SMOKER: |
343 - | if (slot == 2) { |
344 - | type = InventoryType.SlotType.RESULT; |
345 - | } else if (slot == 1) { |
346 - | type = InventoryType.SlotType.FUEL; |
347 - | } else { |
348 - | type = InventoryType.SlotType.CRAFTING; |
349 - | } |
350 - | break; |
351 - | case BREWING: |
352 - | if (slot == 3) { |
353 - | type = InventoryType.SlotType.FUEL; |
354 - | } else { |
355 - | type = InventoryType.SlotType.CRAFTING; |
356 - | } |
357 - | break; |
358 - | case ENCHANTING: |
359 - | type = InventoryType.SlotType.CRAFTING; |
360 - | break; |
361 - | case WORKBENCH: |
362 - | case CRAFTING: |
363 - | if (slot == 0) { |
364 - | type = InventoryType.SlotType.RESULT; |
365 - | } else { |
366 - | type = InventoryType.SlotType.CRAFTING; |
367 - | } |
368 - | break; |
369 - | case BEACON: |
370 - | type = InventoryType.SlotType.CRAFTING; |
371 - | break; |
372 - | case ANVIL: |
373 - | case SMITHING: |
374 - | case CARTOGRAPHY: |
375 - | case GRINDSTONE: |
376 - | case MERCHANT: |
377 - | if (slot == 2) { |
378 - | type = InventoryType.SlotType.RESULT; |
379 - | } else { |
380 - | type = InventoryType.SlotType.CRAFTING; |
381 - | } |
382 - | break; |
383 - | case STONECUTTER: |
384 - | if (slot == 1) { |
385 - | type = InventoryType.SlotType.RESULT; |
386 - | } else { |
387 - | type = InventoryType.SlotType.CRAFTING; |
388 - | } |
389 - | break; |
390 - | case LOOM: |
391 - | case SMITHING_NEW: |
392 - | if (slot == 3) { |
393 - | type = InventoryType.SlotType.RESULT; |
394 - | } else { |
395 - | type = InventoryType.SlotType.CRAFTING; |
396 - | } |
397 - | break; |
398 - | default: |
399 - | // Nothing to do, it's a CONTAINER slot |
400 - | } |
401 - | } else { |
402 - | if (slot < 0) { |
403 - | type = InventoryType.SlotType.OUTSIDE; |
404 - | } else if (this.getType() == InventoryType.CRAFTING) { // Also includes creative inventory |
405 - | if (slot < 9) { |
406 - | type = InventoryType.SlotType.ARMOR; |
407 - | } else if (slot > 35) { |
408 - | type = InventoryType.SlotType.QUICKBAR; |
409 - | } |
410 - | } else if (slot >= (this.countSlots() - (9 + 4 + 1))) { // Quickbar, Armor, Offhand |
411 - | type = InventoryType.SlotType.QUICKBAR; |
412 - | } |
413 - | } |
414 - | return type; |
415 - | } |
245 + | public InventoryType.SlotType getSlotType(int slot); |
416 246 | |
417 247 | /** |
418 248 | * Closes the inventory view. |
419 249 | */ |
420 - | public final void close() { |
421 - | getPlayer().closeInventory(); |
422 - | } |
250 + | public void close(); |
423 251 | |
424 252 | /** |
425 253 | * Check the total number of slots in this view, combining the upper and |
426 254 | * lower inventories. |
427 255 | * <p> |
428 256 | * Note though that it's possible for this to be greater than the sum of |
429 257 | * the two inventories if for example some slots are not being used. |
430 258 | * |
431 259 | * @return The total size |
432 260 | */ |
433 - | public final int countSlots() { |
434 - | return getTopInventory().getSize() + getBottomInventory().getSize(); |
435 - | } |
261 + | public int countSlots(); |
436 262 | |
437 263 | /** |
438 264 | * Sets an extra property of this inventory if supported by that |
439 265 | * inventory, for example the state of a progress bar. |
440 266 | * |
441 267 | * @param prop the window property to update |
442 268 | * @param value the new value for the window property |
443 269 | * @return true if the property was updated successfully, false if the |
444 270 | * property is not supported by that inventory |
445 271 | */ |
446 - | public final boolean setProperty( Property prop, int value) { |
447 - | return getPlayer().setWindowProperty(prop, value); |
448 - | } |
272 + | public boolean setProperty( Property prop, int value); |
449 273 | |
450 274 | /** |
451 275 | * Get the title of this inventory window. |
452 276 | * |
453 277 | * @return The title. |
454 278 | */ |
455 279 | |
456 - | public abstract String getTitle(); |
280 + | public String getTitle(); |
457 281 | |
458 282 | /** |
459 283 | * Get the original title of this inventory window, before any changes were |
460 284 | * made using {@link #setTitle(String)}. |
461 285 | * |
462 286 | * @return the original title |
463 287 | */ |
464 288 | |
465 - | public abstract String getOriginalTitle(); |
289 + | public String getOriginalTitle(); |
466 290 | |
467 291 | /** |
468 292 | * Sets the title of this inventory window to the specified title if the |
469 293 | * inventory window supports it. |
470 294 | * <p> |
471 295 | * Note if the inventory does not support titles that can be changed (ie, it |
472 296 | * is not creatable or viewed by a player), then this method will throw an |
473 297 | * exception. |
474 298 | * |
475 299 | * @param title The new title. |
476 300 | */ |
477 - | public abstract void setTitle( String title); |
301 + | public void setTitle( String title); |
478 302 | } |