Implement tool replacement for stack replacer

This commit is contained in:
Gabriel Tofvesson 2021-05-02 18:46:38 +02:00
parent ad00a02261
commit 511e689e0c

View File

@ -5,6 +5,8 @@ import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
@ -24,21 +26,75 @@ public class StackReplaceListener implements Listener {
@EventHandler
public void onBlockPlacedEvent(final BlockPlaceEvent event) {
final ItemStack usedItemStack = event.getItemInHand();
if (findAndMoveSimilarStack(event.getItemInHand(), event.getHand(), event.getPlayer().getInventory(), CompareFunc.defaultFunc()))
logger.fine(LOG_PLUGIN_NAME + " Moved stack into empty hand for player " + event.getPlayer().getName());
}
@EventHandler
public void onPlayerItemBreakEvent(final PlayerItemBreakEvent event) {
final PlayerInventory inv = event.getPlayer().getInventory();
final ItemStack used = event.getBrokenItem();
final EquipmentSlot slot;
if (used.equals(inv.getBoots())) slot = EquipmentSlot.FEET;
else if (used.equals(inv.getLeggings())) slot = EquipmentSlot.LEGS;
else if (used.equals(inv.getChestplate())) slot = EquipmentSlot.CHEST;
else if (used.equals(inv.getHelmet())) slot = EquipmentSlot.HEAD;
else if (used.equals(inv.getItemInOffHand())) slot = EquipmentSlot.OFF_HAND;
else if (used.equals(inv.getItemInMainHand())) slot = EquipmentSlot.HAND;
else return; // No clue what broke
if (findAndMoveSimilarStack(used, slot, inv, CompareFunc.toolFunc()))
logger.fine(LOG_PLUGIN_NAME + " Moved tool into empty hand for player " + event.getPlayer().getName());
}
private boolean findAndMoveSimilarStack(
final ItemStack usedItemStack,
final EquipmentSlot target,
final PlayerInventory inventory,
final CompareFunc compareFunc) {
if (usedItemStack.getAmount() == 1) {
final PlayerInventory inv = event.getPlayer().getInventory();
for (int i = Math.min(inv.getSize() - 1, MAX_MAIN_INV); i >= 0 ; --i) {
final ItemStack checkStack = inv.getItem(i);
if (i != inv.getHeldItemSlot() && usedItemStack.isSimilar(checkStack)) {
for (int i = Math.min(inventory.getSize() - 1, MAX_MAIN_INV); i >= 0 ; --i) {
final ItemStack checkStack = inventory.getItem(i);
if (i != inventory.getHeldItemSlot() && compareFunc.isSimilar(usedItemStack, checkStack)) {
// To prevent race-condition dupes, remove item before putting it in players hand
inv.setItem(i, new ItemStack(Material.AIR, 0));
inv.setItem(event.getHand(), checkStack);
inventory.setItem(i, new ItemStack(Material.AIR, 0));
inventory.setItem(target, checkStack);
logger.fine(LOG_PLUGIN_NAME + " Moved stack into empty hand for player " + event.getPlayer().getName());
break;
return true;
}
}
}
return false;
}
/**
* Functional interface for determining when two item stacks are equivalent
*
* Note: The comparison should represent an equivalence relation (especially, it should be symmetric)
*/
private interface CompareFunc {
boolean isSimilar(final ItemStack i1, final ItemStack i2);
static CompareFunc defaultFunc() { return ItemStack::isSimilar; }
static CompareFunc toolFunc() {
return (i1, i2) -> {
final boolean isNull1 = i1 == null;
final boolean isNull2 = i2 == null;
if (isNull1 || isNull2)
return isNull1 == isNull2; // This should really never return true
final Material m1 = i1.getType();
final Material m2 = i2.getType();
// If the material name has an underscore, it probably has material type alternatives
if (m1.name().contains("_"))
return m2.name().endsWith(m1.name().substring(i1.getType().name().lastIndexOf('_')));
else
return m2.equals(m1);
};
}
}
}