Created
April 15, 2013 18:29
-
-
Save aadnk/5390227 to your computer and use it in GitHub Desktop.
Player consume/food listener.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example; | |
import java.util.Map; | |
import java.util.WeakHashMap; | |
import org.bukkit.Material; | |
import org.bukkit.entity.Player; | |
import org.bukkit.event.EventHandler; | |
import org.bukkit.event.Listener; | |
import org.bukkit.event.block.Action; | |
import org.bukkit.event.inventory.InventoryClickEvent; | |
import org.bukkit.event.player.PlayerInteractEvent; | |
import org.bukkit.inventory.ItemStack; | |
/** | |
* Adds a simple player food listener. | |
* <p> | |
* Remember to register it as an event listener. | |
* | |
* @author Kristian | |
*/ | |
public abstract class ConsumeListener implements Listener { | |
private static class ConsumeData { | |
private final ItemStack stack; | |
private final int foodLevel; | |
private ConsumeData(ItemStack stack, int foodLevel) { | |
this.stack = stack; | |
this.foodLevel = foodLevel; | |
} | |
public ItemStack getStack() { | |
return stack; | |
} | |
public int getFoodLevel() { | |
return foodLevel; | |
} | |
} | |
private Map<Player, ConsumeData> consumeCandidate = new WeakHashMap<Player, ConsumeData>(); | |
@EventHandler | |
public void onPlayerInteract(PlayerInteractEvent e) { | |
// There's no PlayerConsumeEvent in Bukkit, so we have to detect food consumption by the right click instead | |
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) { | |
Player player = e.getPlayer(); | |
ConsumeData previous = consumeCandidate.get(player); | |
ItemStack current = player.getItemInHand(); | |
// Possible food consumption | |
if (previous != null) { | |
ItemStack subtracted = subtract(previous.getStack(), current); | |
// If they're not equal, the item must have been consumed | |
if (subtracted != null) { | |
onPlayerConsume(player, previous.getFoodLevel(), subtracted); | |
} | |
} | |
// Start of the consume sequence of events | |
if (current != null && current.getType().isEdible()) { | |
ConsumeData data = new ConsumeData(current.clone(), player.getFoodLevel()); | |
// Wait for the next interact event | |
consumeCandidate.put(player, data); | |
} else { | |
// Clean up | |
consumeCandidate.remove(player); | |
} | |
} | |
} | |
@EventHandler | |
public void onInventoryClick(InventoryClickEvent e) { | |
// Players cannot perform inventory events during food consumption, and | |
// we must be careful so that our consumption identification doesn't mistake | |
// moving some items for consumption | |
consumeCandidate.remove(e.getWhoClicked()); | |
} | |
private ItemStack subtract(ItemStack a, ItemStack b) { | |
if (getMaterial(a) == getMaterial(b)) { | |
int remainder = a.getAmount() - b.getAmount(); | |
// Decrement the count | |
if (remainder > 0) { | |
ItemStack copy = a.clone(); | |
copy.setAmount(remainder); | |
return copy; | |
} | |
// Nothing subtracted | |
return null; | |
} else if (b == null) { | |
return a; | |
} else { | |
// Not the same thing - cannot subtract | |
return null; | |
} | |
} | |
private Material getMaterial(ItemStack stack) { | |
return stack != null ? stack.getType() : null; | |
} | |
/** | |
* Invoked a player has consumed a given item. | |
* @param player - the player. | |
* @param prevFoodLevel - the food level before the consume event. | |
* @param item - the item that was consumed. | |
*/ | |
public abstract void onPlayerConsume(Player player, int prevFoodLevel, ItemStack item); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment