Skip to content

Instantly share code, notes, and snippets.

@aadnk
Created April 15, 2013 18:29
Show Gist options
  • Save aadnk/5390227 to your computer and use it in GitHub Desktop.
Save aadnk/5390227 to your computer and use it in GitHub Desktop.
Player consume/food listener.
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