Rewrite Inventory Handling (#5021)

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

Complete refactor of inventory handling across the plugin. This simplifies various commands, and aims to resolve issues aon various different MC versions and inconsistencies between parts of the plugin.

Fixes https://github.com/EssentialsX/Essentials/issues/3810
Fixes https://github.com/EssentialsX/Essentials/issues/4248
This commit is contained in:
Josh Roy 2022-12-24 12:58:51 -05:00 committed by GitHub
parent db10678095
commit 6ec4c97ddd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 646 additions and 518 deletions

View File

@ -1,5 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import net.ess3.api.IEssentials;
import org.bukkit.GameMode;
@ -45,7 +46,7 @@ public class EssentialsBlockListener implements Listener {
if (is != null && is.getType() != null && !MaterialUtil.isAir(is.getType())) {
final ItemStack cloneIs = is.clone();
cloneIs.setAmount(1);
user.getBase().getInventory().addItem(cloneIs);
Inventories.addItem(user.getBase(), cloneIs);
user.getBase().updateInventory();
}
});

View File

@ -1,6 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import org.bukkit.Location;
@ -52,12 +52,12 @@ public class EssentialsEntityListener implements Listener {
if (eDefend instanceof Player) {
onPlayerVsPlayerDamage(event, (Player) eDefend, attacker);
} else if (eDefend instanceof Ageable) {
final ItemStack hand = attacker.getBase().getItemInHand();
final ItemStack hand = Inventories.getItemInMainHand(attacker.getBase());
if (ess.getSettings().isMilkBucketEasterEggEnabled()
&& hand != null && hand.getType() == Material.MILK_BUCKET) {
((Ageable) eDefend).setBaby();
hand.setType(Material.BUCKET);
attacker.getBase().setItemInHand(hand);
Inventories.setItemInMainHand(attacker.getBase(), hand);
attacker.getBase().updateInventory();
event.setCancelled(true);
}
@ -98,7 +98,7 @@ public class EssentialsEntityListener implements Listener {
}
private void onPlayerVsPlayerPowertool(final EntityDamageByEntityEvent event, final Player defender, final User attacker) {
final List<String> commandList = attacker.getPowertool(attacker.getBase().getItemInHand());
final List<String> commandList = attacker.getPowertool(Inventories.getItemInHand(attacker.getBase()));
if (commandList != null && !commandList.isEmpty()) {
for (final String tempCommand : commandList) {
final String command = powertoolPlayer.matcher(tempCommand).replaceAll(defender.getName());
@ -196,73 +196,23 @@ public class EssentialsEntityListener implements Listener {
final ISettings.KeepInvPolicy vanish = ess.getSettings().getVanishingItemsPolicy();
final ISettings.KeepInvPolicy bind = ess.getSettings().getBindingItemsPolicy();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01) && (vanish != ISettings.KeepInvPolicy.KEEP || bind != ISettings.KeepInvPolicy.KEEP)) {
for (final ItemStack stack : event.getEntity().getInventory()) {
if (stack != null && !MaterialUtil.isAir(stack.getType())) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack);
event.getEntity().getInventory().remove(stack);
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
event.getEntity().getInventory().remove(stack);
} else if (bind == ISettings.KeepInvPolicy.DROP) {
event.getEntity().getInventory().remove(stack);
event.getDrops().add(stack);
}
Inventories.removeItems(user.getBase(), stack -> {
if (vanish != ISettings.KeepInvPolicy.KEEP && stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack.clone());
}
return true;
}
}
// Now check armor
final ItemStack[] armor = event.getEntity().getInventory().getArmorContents();
for (int i = 0; i < armor.length; i++) {
final ItemStack stack = armor[i];
if (stack != null && !MaterialUtil.isAir(stack.getType())) {
if (stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE)) {
if (vanish == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (vanish == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
}
if (stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DELETE) {
armor[i] = null;
} else if (bind == ISettings.KeepInvPolicy.DROP) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
armor[i] = null;
}
if (bind != ISettings.KeepInvPolicy.KEEP && stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE)) {
if (bind == ISettings.KeepInvPolicy.DROP) {
event.getDrops().add(stack.clone());
}
return true;
}
}
event.getEntity().getInventory().setArmorContents(armor);
// Now check offhand
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01)) {
final ItemStack stack = event.getEntity().getInventory().getItemInOffHand();
//noinspection ConstantConditions
if (stack != null && !MaterialUtil.isAir(stack.getType())) {
final boolean isVanish = stack.getEnchantments().containsKey(Enchantment.VANISHING_CURSE);
final boolean isBind = stack.getEnchantments().containsKey(Enchantment.BINDING_CURSE);
if (isVanish || isBind) {
event.getEntity().getInventory().setItemInOffHand(null);
if ((isVanish && vanish == ISettings.KeepInvPolicy.DROP) || (isBind && bind == ISettings.KeepInvPolicy.DROP)) {
if (!event.getDrops().contains(stack)) {
event.getDrops().add(stack);
}
}
}
}
}
return false;
}, true);
}
}
}

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.Commandfireball;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.TextInput;
@ -559,7 +560,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor {
final User user = ess.getUser(event.getPlayer());
final ItemStack stack = new ItemStack(Material.EGG, 1);
if (user.hasUnlimited(stack)) {
user.getBase().getInventory().addItem(stack);
Inventories.addItem(user.getBase(), stack);
user.getBase().updateInventory();
}
}

View File

@ -2,23 +2,22 @@ package com.earth2me.essentials;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.commands.NoChargeException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.textreader.IText;
import com.earth2me.essentials.textreader.KeywordReplacer;
import com.earth2me.essentials.textreader.SimpleTextInput;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IEssentials;
import net.ess3.api.events.KitClaimEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
@ -214,57 +213,34 @@ public class Kit {
stack = metaStack.getItemStack();
}
if (autoEquip) {
final Material material = stack.getType();
final PlayerInventory inventory = user.getBase().getInventory();
if (MaterialUtil.isHelmet(material) && isEmptyStack(inventory.getHelmet())) {
inventory.setHelmet(stack);
continue;
} else if (MaterialUtil.isChestplate(material) && isEmptyStack(inventory.getChestplate())) {
inventory.setChestplate(stack);
continue;
} else if (MaterialUtil.isLeggings(material) && isEmptyStack(inventory.getLeggings())) {
inventory.setLeggings(stack);
continue;
} else if (MaterialUtil.isBoots(material) && isEmptyStack(inventory.getBoots())) {
inventory.setBoots(stack);
continue;
}
}
itemList.add(stack);
}
final Map<Integer, ItemStack> overfilled;
final boolean allowOversizedStacks = user.isAuthorized("essentials.oversizedstacks");
final int maxStackSize = user.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0;
final boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull();
if (isDropItemsIfFull) {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
final ItemStack[] itemArray = itemList.toArray(new ItemStack[0]);
if (!isDropItemsIfFull && !Inventories.hasSpace(user.getBase(), maxStackSize, autoEquip, itemArray)) {
user.sendMessage(tl("kitInvFullNoDrop"));
return false;
}
final Map<Integer, ItemStack> leftover = Inventories.addItem(user.getBase(), maxStackSize, autoEquip, itemArray);
if (!isDropItemsIfFull && !leftover.isEmpty()) {
// Inventories#hasSpace should prevent this state from EVER being reached; If it does, something has gone terribly wrong, and we should just give up and hope people report it :(
throw new IllegalStateException("Something has gone terribly wrong while adding items to the user's inventory. Please report this to the EssentialsX developers. Items left over: " + leftover + ". Original items: " + Arrays.toString(itemArray));
}
for (final ItemStack itemStack : leftover.values()) {
int spillAmount = itemStack.getAmount();
if (maxStackSize != 0) {
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
for (final ItemStack itemStack : overfilled.values()) {
int spillAmount = itemStack.getAmount();
if (!allowOversizedStacks) {
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
}
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
} else {
if (allowOversizedStacks) {
overfilled = InventoryWorkaround.addAllOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), itemList.toArray(new ItemStack[0]));
} else {
overfilled = InventoryWorkaround.addAllItems(user.getBase().getInventory(), itemList.toArray(new ItemStack[0]));
}
if (overfilled != null) {
user.sendMessage(tl("kitInvFullNoDrop"));
return false;
while (spillAmount > 0) {
user.getWorld().dropItemNaturally(user.getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
spew = true;
}
user.getBase().updateInventory();
@ -291,8 +267,4 @@ public class Kit {
}
return true;
}
private boolean isEmptyStack(ItemStack stack) {
return stack == null || MaterialUtil.isAir(stack.getType());
}
}

View File

@ -1,6 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@ -362,8 +362,8 @@ public enum MobData {
((Horse) spawned).getInventory().setArmor(new ItemStack((Material) this.value, 1));
} else if (this.type.equals(EntityType.ZOMBIE.getEntityClass()) || this.type.equals(EntityType.SKELETON)) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack((Material) this.value, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
} else if (this.value.equals(Data.RAID_LEADER)) {
((Raider) spawned).setPatrolLeader(true);

View File

@ -1,7 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.Mob.MobException;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.LocationUtil;
import com.earth2me.essentials.utils.StringUtil;
@ -251,8 +251,8 @@ public final class SpawnMob {
private static void defaultMobData(final EntityType type, final Entity spawned) {
if (type == EntityType.SKELETON) {
final EntityEquipment invent = ((LivingEntity) spawned).getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack(Material.BOW, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
if (type == MobCompat.ZOMBIFIED_PIGLIN) {
@ -260,8 +260,8 @@ public final class SpawnMob {
setVillager(zombie, false);
final EntityEquipment invent = zombie.getEquipment();
InventoryWorkaround.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
InventoryWorkaround.setItemInMainHandDropChance(invent, 0.1f);
Inventories.setItemInMainHand(invent, new ItemStack(GOLDEN_SWORD, 1));
Inventories.setItemInMainHandDropChance(invent, 0.1f);
}
if (type == EntityType.ZOMBIE) {

View File

@ -1,6 +1,6 @@
package com.earth2me.essentials;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.craftbukkit.SetExpFix;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
@ -8,7 +8,6 @@ import net.ess3.api.IEssentials;
import net.ess3.api.IUser;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Location;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import java.io.File;
@ -16,6 +15,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
@ -197,7 +197,7 @@ public class Trade {
return;
}
if (getItemStack() != null && !user.getBase().getInventory().containsAtLeast(itemStack, itemStack.getAmount())) {
if (getItemStack() != null && !Inventories.containsAtLeast(user.getBase(), itemStack, itemStack.getAmount())) {
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), ess.getItemDb().name(getItemStack()))));
return;
}
@ -225,52 +225,33 @@ public class Trade {
user.giveMoney(getMoney());
}
if (getItemStack() != null) {
// This stores the would be overflow
final Map<Integer, ItemStack> overFlow = InventoryWorkaround.addAllItems(user.getBase().getInventory(), getItemStack());
if (type == OverflowType.ABORT && !Inventories.hasSpace(user.getBase(), 0, false, getItemStack())) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space ");
}
return Collections.singletonMap(0, getItemStack());
}
if (overFlow != null) {
switch (type) {
case ABORT:
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space ");
final Map<Integer, ItemStack> leftover = Inventories.addItem(user.getBase(), getItemStack());
user.getBase().updateInventory();
if (!leftover.isEmpty()) {
if (type == OverflowType.RETURN) {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + leftover.get(0).toString());
}
return leftover;
} else {
for (final ItemStack itemStack : leftover.values()) {
int spillAmount = itemStack.getAmount();
itemStack.setAmount(Math.min(spillAmount, itemStack.getMaxStackSize()));
while (spillAmount > 0) {
user.getBase().getWorld().dropItemNaturally(user.getBase().getLocation(), itemStack);
spillAmount -= itemStack.getAmount();
}
return overFlow;
case RETURN:
// Pay the user the items, and return overflow
final Map<Integer, ItemStack> returnStack = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack());
user.getBase().updateInventory();
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " with overflow " + returnStack.get(0).toString());
}
return returnStack;
case DROP:
// Pay the users the items directly, and drop the rest, will always return no overflow.
final Map<Integer, ItemStack> leftOver = InventoryWorkaround.addItems(user.getBase().getInventory(), getItemStack());
final Location loc = user.getBase().getLocation();
for (final ItemStack loStack : leftOver.values()) {
final int maxStackSize = loStack.getType().getMaxStackSize();
final int stacks = loStack.getAmount() / maxStackSize;
final int leftover = loStack.getAmount() % maxStackSize;
final Item[] itemStacks = new Item[stacks + (leftover > 0 ? 1 : 0)];
for (int i = 0; i < stacks; i++) {
final ItemStack stack = loStack.clone();
stack.setAmount(maxStackSize);
itemStacks[i] = loc.getWorld().dropItem(loc, stack);
}
if (leftover > 0) {
final ItemStack stack = loStack.clone();
stack.setAmount(leftover);
itemStacks[stacks] = loc.getWorld().dropItem(loc, stack);
}
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftOver.get(0).toString());
}
break;
}
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftover.get(0).toString());
}
}
} else if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "paying " + user.getName() + " itemstack " + getItemStack().toString());
@ -315,11 +296,11 @@ public class Trade {
if (ess.getSettings().isDebug()) {
ess.getLogger().log(Level.INFO, "charging user " + user.getName() + " itemstack " + getItemStack().toString());
}
if (!user.getBase().getInventory().containsAtLeast(getItemStack(), getItemStack().getAmount())) {
if (!Inventories.containsAtLeast(user.getBase(), getItemStack(), getItemStack().getAmount())) {
future.completeExceptionally(new ChargeException(tl("missingItems", getItemStack().getAmount(), getItemStack().getType().toString().toLowerCase(Locale.ENGLISH).replace("_", " "))));
return;
}
user.getBase().getInventory().removeItem(getItemStack());
Inventories.removeItemAmount(user.getBase(), getItemStack(), getItemStack().getAmount());
user.getBase().updateInventory();
}
if (command != null) {

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials;
import com.earth2me.essentials.commands.IEssentialsCommand;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.messaging.IMessageRecipient;
@ -27,7 +28,6 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@ -1141,12 +1141,7 @@ public class User extends UserData implements Comparable<User>, IMessageRecipien
* Returns the {@link ItemStack} in the main hand or off-hand. If the main hand is empty then the offhand item is returned - also nullable.
*/
public ItemStack getItemInHand() {
if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) {
return getBase().getInventory().getItemInHand();
} else {
final PlayerInventory inventory = getBase().getInventory();
return inventory.getItemInMainHand() != null ? inventory.getItemInMainHand() : inventory.getItemInOffHand();
}
return Inventories.getItemInHand(getBase());
}
@Override

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials;
import com.earth2me.essentials.commands.NotEnoughArgumentsException;
import com.earth2me.essentials.config.ConfigurateUtil;
import com.earth2me.essentials.config.EssentialsConfiguration;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@ -101,7 +102,7 @@ public class Worth implements IConf {
}
int max = 0;
for (final ItemStack s : user.getBase().getInventory().getContents()) {
for (final ItemStack s : Inventories.getInventory(user.getBase(), false)) {
if (s == null || !s.isSimilar(is)) {
continue;
}

View File

@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.google.common.collect.Lists;
import org.bukkit.Material;
@ -52,7 +52,7 @@ public class Commandbook extends EssentialsCommand {
if (isAuthor(bmeta, player) || user.isAuthorized("essentials.book.others")) {
final ItemStack newItem = new ItemStack(WRITABLE_BOOK, item.getAmount());
newItem.setItemMeta(bmeta);
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
Inventories.setItemInMainHand(user.getBase(), newItem);
user.sendMessage(tl("editBookContents"));
} else {
throw new Exception(tl("denyBookEdit"));
@ -65,7 +65,7 @@ public class Commandbook extends EssentialsCommand {
}
final ItemStack newItem = new ItemStack(Material.WRITTEN_BOOK, item.getAmount());
newItem.setItemMeta(bmeta);
InventoryWorkaround.setItemInMainHand(user.getBase(), newItem);
Inventories.setItemInMainHand(user.getBase(), newItem);
user.sendMessage(tl("bookLocked"));
} else {
throw new Exception(tl("holdBook"));

View File

@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@ -22,8 +22,6 @@ import java.util.Set;
import static com.earth2me.essentials.I18n.tl;
public class Commandclearinventory extends EssentialsCommand {
private static final int BASE_AMOUNT = 100000;
private static final int EXTENDED_CAP = 8;
public Commandclearinventory() {
@ -114,38 +112,30 @@ public class Commandclearinventory extends EssentialsCommand {
}
}
if (type == ClearHandlerType.ALL_EXCEPT_ARMOR) {
if (type != ClearHandlerType.SPECIFIC_ITEM) {
final boolean armor = type == ClearHandlerType.ALL_INCLUDING_ARMOR;
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllItems", player.getDisplayName()));
sender.sendMessage(tl(armor ? "inventoryClearingAllArmor" : "inventoryClearingAllItems", player.getDisplayName()));
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
} else if (type == ClearHandlerType.ALL_INCLUDING_ARMOR) {
if (showExtended) {
sender.sendMessage(tl("inventoryClearingAllArmor", player.getDisplayName()));
}
InventoryWorkaround.clearInventoryNoArmor(player.getInventory());
InventoryWorkaround.setItemInOffHand(player, null);
player.getInventory().setArmorContents(null);
Inventories.removeItems(player, item -> true, armor);
} else {
for (final Item item : items) {
final ItemStack stack = new ItemStack(item.getMaterial());
if (VersionUtil.PRE_FLATTENING) {
//noinspection deprecation
stack.setDurability(item.getData());
}
// amount -1 means all items will be cleared
if (amount == -1) {
stack.setAmount(BASE_AMOUNT);
final ItemStack removedStack = player.getInventory().removeItem(stack).get(0);
final int removedAmount = BASE_AMOUNT - removedStack.getAmount() + InventoryWorkaround.clearItemInOffHand(player, stack);
final int removedAmount = Inventories.removeItemSimilar(player, stack, true);
if (removedAmount > 0 || showExtended) {
sender.sendMessage(tl("inventoryClearingStack", removedAmount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
}
} else {
stack.setAmount(amount < 0 ? 1 : amount);
if (player.getInventory().containsAtLeast(stack, amount)) {
if (Inventories.removeItemAmount(player, stack, amount)) {
sender.sendMessage(tl("inventoryClearingStack", amount, stack.getType().toString().toLowerCase(Locale.ENGLISH), player.getDisplayName()));
player.getInventory().removeItem(stack);
} else {
if (showExtended) {
sender.sendMessage(tl("inventoryClearFail", player.getDisplayName(), amount, stack.getType().toString().toLowerCase(Locale.ENGLISH)));
@ -203,7 +193,7 @@ public class Commandclearinventory extends EssentialsCommand {
}
private String formatCommand(final String commandLabel, final String[] args) {
return "/" + commandLabel + " " + StringUtil.joinList(" ", args);
return "/" + commandLabel + " " + StringUtil.joinList(" ", (Object[]) args);
}
private enum ClearHandlerType {

View File

@ -4,6 +4,7 @@ import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.MaxMoneyException;
import org.bukkit.Material;
@ -39,7 +40,7 @@ public class Commandcondense extends EssentialsCommand {
if (args.length > 0) {
is = ess.getItemDb().getMatching(user, args);
} else {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), false)) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
@ -85,7 +86,7 @@ public class Commandcondense extends EssentialsCommand {
int amount = 0;
for (final ItemStack contents : user.getBase().getInventory().getContents()) {
for (final ItemStack contents : Inventories.getInventory(user.getBase(), false)) {
if (contents != null && contents.isSimilar(stack)) {
amount += contents.getAmount();
}

View File

@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.DateUtil;
import com.earth2me.essentials.utils.PasteUtil;
import org.bukkit.Material;
@ -37,7 +38,7 @@ public class Commandcreatekit extends EssentialsCommand {
// Command handler will auto fail if this fails.
final long delay = Long.parseLong(args[1]);
final String kitname = args[0];
final ItemStack[] items = user.getBase().getInventory().getContents();
final ItemStack[] items = Inventories.getInventory(user.getBase(), true);
final List<String> list = new ArrayList<>();
boolean useSerializationProvider = ess.getSettings().isUseBetterKits();

View File

@ -3,7 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.Enchantments;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import org.bukkit.Material;
@ -57,7 +57,7 @@ public class Commandenchant extends EssentialsCommand {
final MetaItemStack metaStack = new MetaItemStack(stack);
final Enchantment enchantment = metaStack.getEnchantment(user, args[0]);
metaStack.addEnchantment(user.getSource(), ess.getSettings().allowUnsafeEnchantments() && user.isAuthorized("essentials.enchantments.allowunsafe"), enchantment, level);
InventoryWorkaround.setItemInMainHand(user.getBase(), metaStack.getItemStack());
Inventories.setItemInMainHand(user.getBase(), metaStack.getItemStack());
user.getBase().updateInventory();
final String enchantName = enchantment.getName().toLowerCase(Locale.ENGLISH).replace('_', ' ');
if (level == 0) {

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.EssentialsUpgrade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.economy.EconomyLayer;
import com.earth2me.essentials.economy.EconomyLayers;
import com.earth2me.essentials.userstorage.ModernUserMap;
@ -22,11 +23,13 @@ import com.google.gson.JsonPrimitive;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
@ -154,6 +157,10 @@ public class Commandessentials extends EssentialsCommand {
runUserMap(sender, args);
break;
case "itemtest":
runItemTest(server, sender, commandLabel, args);
break;
// "#EasterEgg"
case "nya":
case "nyan":
@ -168,6 +175,56 @@ public class Commandessentials extends EssentialsCommand {
}
}
public void runItemTest(Server server, CommandSource sender, String commandLabel, String[] args) {
if (!sender.isAuthorized("essentials.itemtest", ess) || args.length < 2 || !sender.isPlayer()) {
return;
}
final Player player = sender.getPlayer();
assert player != null;
switch (args[1]) {
case "slot": {
if (args.length < 3) {
return;
}
player.getInventory().setItem(Integer.parseInt(args[2]), new ItemStack(Material.DIRT));
break;
}
case "overfill": {
sender.sendMessage(Inventories.addItem(player, 42, false, new ItemStack(Material.DIAMOND_SWORD, 1), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIRT, 32)).toString());
break;
}
case "overfill2": {
if (args.length < 4) {
return;
}
final boolean armor = Boolean.parseBoolean(args[2]);
final boolean add = Boolean.parseBoolean(args[3]);
final ItemStack[] items = new ItemStack[]{new ItemStack(Material.DIAMOND_SWORD, 1), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIRT, 32), new ItemStack(Material.DIAMOND_HELMET, 4), new ItemStack(Material.CHAINMAIL_LEGGINGS, 1)};
if (Inventories.hasSpace(player, 0, armor, items)) {
if (add) {
sender.sendMessage(Inventories.addItem(player, 0, armor, items).toString());
}
sender.sendMessage("SO MUCH SPACE!");
} else {
sender.sendMessage("No space!");
}
break;
}
case "remove": {
if (args.length < 3) {
return;
}
Inventories.removeItemExact(player, new ItemStack(Material.PUMPKIN, 1), Boolean.parseBoolean(args[2]));
break;
}
default: {
break;
}
}
}
// Displays the command's usage.
private void showUsage(final CommandSource sender) throws Exception {
throw new NotEnoughArgumentsException();

View File

@ -3,7 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
@ -81,13 +81,8 @@ public class Commandgive extends EssentialsLoopCommand {
final ItemStack finalStack = stack;
loopOnlinePlayersConsumer(server, sender, false, true, args[0], player -> {
sender.sendMessage(tl("giveSpawn", finalStack.getAmount(), itemName, player.getDisplayName()));
final Map<Integer, ItemStack> leftovers;
if (player.isAuthorized("essentials.oversizedstacks")) {
leftovers = InventoryWorkaround.addOversizedItems(player.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), finalStack);
} else {
leftovers = InventoryWorkaround.addItems(player.getBase().getInventory(), finalStack);
}
final Map<Integer, ItemStack> leftovers = Inventories.addItem(player.getBase(), player.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0, finalStack);
for (final ItemStack item : leftovers.values()) {
if (isDropItemsIfFull) {

View File

@ -1,7 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.TriState;
import com.earth2me.essentials.utils.VersionUtil;
import com.google.common.collect.Lists;
@ -67,7 +67,7 @@ public class Commandhat extends EssentialsCommand {
} else {
final ItemStack air = new ItemStack(Material.AIR);
inv.setHelmet(air);
InventoryWorkaround.addItems(user.getBase().getInventory(), head);
Inventories.addItem(user.getBase(), head);
user.sendMessage(tl("hatRemoved"));
}
}

View File

@ -2,7 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.MetaItemStack;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.google.common.collect.Lists;
import org.bukkit.Material;
import org.bukkit.Server;
@ -63,11 +63,7 @@ public class Commanditem extends EssentialsCommand {
final String displayName = stack.getType().toString().toLowerCase(Locale.ENGLISH).replace('_', ' ');
user.sendMessage(tl("itemSpawn", stack.getAmount(), displayName));
if (user.isAuthorized("essentials.oversizedstacks")) {
InventoryWorkaround.addOversizedItems(user.getBase().getInventory(), ess.getSettings().getOversizedStackSize(), stack);
} else {
InventoryWorkaround.addItems(user.getBase().getInventory(), stack);
}
Inventories.addItem(user.getBase(), user.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0, stack);
user.getBase().updateInventory();
}

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
@ -24,8 +25,8 @@ public class Commanditemlore extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack item = user.getBase().getItemInHand();
if (MaterialUtil.isAir(item.getType())) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item == null || MaterialUtil.isAir(item.getType())) {
throw new Exception(tl("itemloreInvalidItem"));
}
@ -73,8 +74,8 @@ public class Commanditemlore extends EssentialsCommand {
} else if (args.length == 2) {
switch (args[0].toLowerCase(Locale.ENGLISH)) {
case "set": {
final ItemStack item = user.getBase().getItemInHand();
if (!MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore()) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item != null && !MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore()) {
final List<String> lineNumbers = new ArrayList<>();
for (int i = 1; i <= item.getItemMeta().getLore().size(); i++) {
lineNumbers.add(String.valueOf(i));
@ -92,8 +93,8 @@ public class Commanditemlore extends EssentialsCommand {
} else if (args.length == 3) {
if (args[0].equalsIgnoreCase("set") && NumberUtil.isInt(args[1])) {
final int i = Integer.parseInt(args[1]);
final ItemStack item = user.getBase().getItemInHand();
if (!MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore() && item.getItemMeta().getLore().size() >= i) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item != null && !MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasLore() && item.getItemMeta().getLore().size() >= i) {
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.itemlore", item.getItemMeta().getLore().get(i - 1)));
}
}

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.TriState;
@ -23,8 +24,8 @@ public class Commanditemname extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final ItemStack item = user.getBase().getItemInHand();
if (MaterialUtil.isAir(item.getType())) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item == null || MaterialUtil.isAir(item.getType())) {
user.sendMessage(tl("itemnameInvalidItem"));
return;
}
@ -50,8 +51,8 @@ public class Commanditemname extends EssentialsCommand {
@Override
protected List<String> getTabCompleteOptions(Server server, User user, String commandLabel, String[] args) {
if (args.length == 1) {
final ItemStack item = user.getBase().getItemInHand();
if (!MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
final ItemStack item = Inventories.getItemInHand(user.getBase());
if (item != null && !MaterialUtil.isAir(item.getType()) && item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
return Lists.newArrayList(FormatUtil.unformatString(user, "essentials.itemname", item.getItemMeta().getDisplayName()));
}
}

View File

@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.CommandSource;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.StringUtil;
import com.google.common.collect.Lists;
import org.bukkit.Material;
@ -22,7 +23,7 @@ public class Commandpowertool extends EssentialsCommand {
@Override
protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception {
final String command = getFinalArg(args, 0);
final ItemStack itemStack = user.getBase().getItemInHand();
final ItemStack itemStack = Inventories.getItemInHand(user.getBase());
powertool(user.getSource(), user, itemStack, command);
}
@ -111,7 +112,7 @@ public class Commandpowertool extends EssentialsCommand {
}
try {
final ItemStack itemStack = user.getBase().getItemInHand();
final ItemStack itemStack = Inventories.getItemInHand(user.getBase());
final List<String> powertools = user.getPowertool(itemStack);
for (final String tool : powertools) {
options.add("r:" + tool);

View File

@ -3,6 +3,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
@ -62,7 +63,7 @@ public class Commandrepair extends EssentialsCommand {
public void repairAll(final User user) throws Exception {
final List<String> repaired = new ArrayList<>();
repairItems(user.getBase().getInventory().getContents(), user, repaired);
repairItems(Inventories.getInventory(user.getBase(), false), user, repaired);
if (user.isAuthorized("essentials.repair.armor")) {
repairItems(user.getBase().getInventory().getArmorContents(), user, repaired);

View File

@ -2,6 +2,7 @@ package com.earth2me.essentials.commands;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.NumberUtil;
import com.google.common.collect.Lists;
import net.ess3.api.events.UserBalanceUpdateEvent;
@ -108,11 +109,11 @@ public class Commandsell extends EssentialsCommand {
//TODO: Prices for Enchantments
final ItemStack ris = is.clone();
ris.setAmount(amount);
if (!user.getBase().getInventory().containsAtLeast(ris, amount)) {
if (!Inventories.containsAtLeast(user.getBase(), ris, amount)) {
// This should never happen.
throw new IllegalStateException("Trying to remove more items than are available.");
}
user.getBase().getInventory().removeItem(ris);
Inventories.removeItemAmount(user.getBase(), ris, ris.getAmount());
user.getBase().updateInventory();
Trade.log("Command", "Sell", "Item", user.getName(), new Trade(ris, ess), user.getName(), new Trade(result, ess), user.getLocation(), user.getMoney(), ess);
user.giveMoney(result, null, UserBalanceUpdateEvent.Cause.COMMAND_SELL);

View File

@ -22,7 +22,7 @@ public class Commandsetworth extends EssentialsCommand {
final ItemStack stack;
final String price;
if (args.length == 1) {
stack = user.getBase().getInventory().getItemInHand();
stack = user.getItemInHand();
price = args[0];
} else {
stack = ess.getItemDb().get(args[0]);

View File

@ -1,7 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.InventoryWorkaround;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.EnumUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.google.common.collect.Lists;
@ -9,7 +9,6 @@ import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.Collections;
import java.util.List;
@ -60,26 +59,21 @@ public class Commandskull extends EssentialsCommand {
}
private void editSkull(final User user, final ItemStack stack, final SkullMeta skullMeta, final String owner, final boolean spawn) {
new BukkitRunnable() {
@Override
public void run() {
//Run this stuff async because SkullMeta#setOwner causes a http request.
skullMeta.setDisplayName("§fSkull of " + owner);
skullMeta.setOwner(owner);
new BukkitRunnable() {
@Override
public void run() {
stack.setItemMeta(skullMeta);
if (spawn) {
InventoryWorkaround.addItems(user.getBase().getInventory(), stack);
user.sendMessage(tl("givenSkull", owner));
return;
}
user.sendMessage(tl("skullChanged", owner));
}
}.runTask(ess);
}
}.runTaskAsynchronously(ess);
ess.runTaskAsynchronously(() -> {
//Run this stuff async because SkullMeta#setOwner causes a http request.
skullMeta.setDisplayName("§fSkull of " + owner);
//noinspection deprecation
skullMeta.setOwner(owner);
ess.scheduleSyncDelayedTask(() -> {
stack.setItemMeta(skullMeta);
if (spawn) {
Inventories.addItem(user.getBase(), stack);
user.sendMessage(tl("givenSkull", owner));
return;
}
user.sendMessage(tl("skullChanged", owner));
});
});
}
@Override

View File

@ -1,6 +1,7 @@
package com.earth2me.essentials.commands;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.inventory.ItemStack;
@ -75,8 +76,8 @@ public class Commandunlimited extends EssentialsCommand {
if (!target.hasUnlimited(stack)) {
message = "enableUnlimited";
enableUnlimited = true;
if (!target.getBase().getInventory().containsAtLeast(stack, stack.getAmount())) {
target.getBase().getInventory().addItem(stack);
if (!Inventories.containsAtLeast(target.getBase(), stack, stack.getAmount())) {
Inventories.addItem(target.getBase(), stack);
}
}

View File

@ -0,0 +1,404 @@
package com.earth2me.essentials.craftbukkit;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public final class Inventories {
private static final int HELM_SLOT = 39;
private static final int CHEST_SLOT = 38;
private static final int LEG_SLOT = 37;
private static final int BOOT_SLOT = 36;
private static final boolean HAS_OFFHAND = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01);
private Inventories() {
}
public static ItemStack getItemInHand(final Player player) {
if (!HAS_OFFHAND) {
//noinspection deprecation
return player.getInventory().getItemInHand();
}
final PlayerInventory inventory = player.getInventory();
final ItemStack main = inventory.getItemInMainHand();
return !isEmpty(main) ? main : inventory.getItemInOffHand();
}
public static ItemStack getItemInMainHand(final Player player) {
if (!HAS_OFFHAND) {
//noinspection deprecation
return player.getInventory().getItemInHand();
}
return player.getInventory().getItemInMainHand();
}
public static void setItemInMainHand(final Player player, final ItemStack stack) {
if (HAS_OFFHAND) {
player.getInventory().setItemInMainHand(stack);
} else {
//noinspection deprecation
player.setItemInHand(stack);
}
}
public static void setItemInMainHand(final EntityEquipment entityEquipment, final ItemStack stack) {
if (HAS_OFFHAND) {
entityEquipment.setItemInMainHand(stack);
} else {
//noinspection deprecation
entityEquipment.setItemInHand(stack);
}
}
public static void setItemInMainHandDropChance(final EntityEquipment entityEquipment, final float chance) {
if (HAS_OFFHAND) {
entityEquipment.setItemInMainHandDropChance(chance);
} else {
//noinspection deprecation
entityEquipment.setItemInHandDropChance(chance);
}
}
public static boolean containsAtLeast(final Player player, final ItemStack item, int amount) {
for (final ItemStack invItem : player.getInventory().getContents()) {
if (isEmpty(invItem)) {
continue;
}
if (invItem.isSimilar(item)) {
amount -= invItem.getAmount();
if (amount <= 0) {
return true;
}
}
}
return false;
}
public static boolean hasSpace(final Player player, final int maxStack, final boolean includeArmor, ItemStack... items) {
items = normalizeItems(cloneItems(items));
final InventoryData inventoryData = parseInventoryData(player.getInventory(), items, maxStack, includeArmor);
final List<Integer> emptySlots = inventoryData.getEmptySlots();
for (final ItemStack item : items) {
if (isEmpty(item)) {
continue;
}
final int itemMax = Math.max(maxStack, item.getMaxStackSize());
final List<Integer> partialSlots = inventoryData.getPartialSlots().get(item);
while (true) {
if (partialSlots == null || partialSlots.isEmpty()) {
if (emptySlots.isEmpty()) {
return false;
}
emptySlots.remove(0);
if (item.getAmount() > itemMax) {
item.setAmount(item.getAmount() - itemMax);
} else {
break;
}
} else {
final int slot = partialSlots.remove(0);
ItemStack existing = player.getInventory().getItem(slot);
if (isEmpty(existing)) {
existing = item.clone();
existing.setAmount(0);
}
final int amount = item.getAmount();
final int existingAmount = existing.getAmount();
if (amount + existingAmount <= itemMax) {
break;
} else {
item.setAmount(amount + existingAmount - itemMax);
}
}
}
}
return true;
}
public static Map<Integer, ItemStack> addItem(final Player player, final ItemStack... items) {
return addItem(player, 0, false, items);
}
public static Map<Integer, ItemStack> addItem(final Player player, final int maxStack, final ItemStack... items) {
return addItem(player, maxStack, false, items);
}
public static Map<Integer, ItemStack> addItem(final Player player, final int maxStack, final boolean allowArmor, ItemStack... items) {
items = normalizeItems(cloneItems(items));
final Map<Integer, ItemStack> leftover = new HashMap<>();
final InventoryData inventoryData = parseInventoryData(player.getInventory(), items, maxStack, allowArmor);
final List<Integer> emptySlots = inventoryData.getEmptySlots();
for (int i = 0; i < items.length; i++) {
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
final int itemMax = Math.max(maxStack, item.getMaxStackSize());
final List<Integer> partialSlots = inventoryData.getPartialSlots().get(item);
while (true) {
if (partialSlots == null || partialSlots.isEmpty()) {
if (emptySlots.isEmpty()) {
leftover.put(i, item);
break;
}
final int slot = emptySlots.remove(0);
if (item.getAmount() > itemMax) {
final ItemStack split = item.clone();
split.setAmount(itemMax);
player.getInventory().setItem(slot, split);
item.setAmount(item.getAmount() - itemMax);
} else {
player.getInventory().setItem(slot, item);
break;
}
} else {
final int slot = partialSlots.remove(0);
ItemStack existing = player.getInventory().getItem(slot);
if (isEmpty(existing)) {
existing = item.clone();
existing.setAmount(0);
}
final int amount = item.getAmount();
final int existingAmount = existing.getAmount();
if (amount + existingAmount <= itemMax) {
existing.setAmount(amount + existingAmount);
player.getInventory().setItem(slot, existing);
break;
} else {
existing.setAmount(itemMax);
player.getInventory().setItem(slot, existing);
item.setAmount(amount + existingAmount - itemMax);
}
}
}
}
return leftover;
}
public static ItemStack[] getInventory(final Player player, final boolean includeArmor) {
final ItemStack[] items = new ItemStack[41];
for (int i = 0; i < items.length; i++) {
if (!includeArmor && isArmorSlot(i)) {
items[i] = null;
continue;
}
items[i] = player.getInventory().getItem(i);
}
return items;
}
public static void removeItemExact(final Player player, final ItemStack toRemove, final boolean includeArmor) {
removeItems(player, itemStack -> itemStack.equals(toRemove), includeArmor);
}
public static int removeItemSimilar(final Player player, final ItemStack toRemove, final boolean includeArmor) {
return removeItems(player, itemStack -> itemStack.isSimilar(toRemove), includeArmor);
}
public static int removeItems(final Player player, final Predicate<ItemStack> removePredicate, final boolean includeArmor) {
int removedAmount = 0;
final ItemStack[] items = player.getInventory().getContents();
for (int i = 0; i < items.length; i++) {
if (!includeArmor && isArmorSlot(i)) {
continue;
}
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
if (removePredicate.test(item)) {
removedAmount += item.getAmount();
item.setAmount(0);
player.getInventory().setItem(i, item);
}
}
return removedAmount;
}
public static boolean removeItemAmount(final Player player, final ItemStack toRemove, int amount) {
final List<Integer> clearSlots = new ArrayList<>();
final ItemStack[] items = player.getInventory().getContents();
for (int i = 0; i < items.length; i++) {
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
if (item.isSimilar(toRemove)) {
if (item.getAmount() >= amount) {
item.setAmount(item.getAmount() - amount);
player.getInventory().setItem(i, item);
for (final int slot : clearSlots) {
clearSlot(player, slot);
}
return true;
} else {
amount -= item.getAmount();
clearSlots.add(i);
}
if (amount == 0) {
for (final int slot : clearSlots) {
clearSlot(player, slot);
}
return true;
}
}
}
return false;
}
public static void clearSlot(final Player player, final int slot) {
final ItemStack item = player.getInventory().getItem(slot);
if (!isEmpty(item)) {
item.setAmount(0);
player.getInventory().setItem(slot, item);
}
}
public static void setSlot(final Player inventory, final int slot, final ItemStack item) {
inventory.getInventory().setItem(slot, item);
}
private static ItemStack[] normalizeItems(final ItemStack[] items) {
if (items.length <= 1) {
return items;
}
final ItemStack[] normalizedItems = new ItemStack[items.length];
int nextNormalizedIndex = 0;
inputLoop:
for (final ItemStack item : items) {
if (isEmpty(item)) {
continue;
}
for (int j = 0; j < nextNormalizedIndex; j++) {
final ItemStack normalizedItem = normalizedItems[j];
if (isEmpty(normalizedItem)) {
continue;
}
if (item.isSimilar(normalizedItem)) {
normalizedItem.setAmount(normalizedItem.getAmount() + item.getAmount());
continue inputLoop;
}
}
normalizedItems[nextNormalizedIndex++] = item;
}
return normalizedItems;
}
private static ItemStack[] cloneItems(final ItemStack[] items) {
final ItemStack[] clonedItems = new ItemStack[items.length];
for (int i = 0; i < items.length; i++) {
final ItemStack item = items[i];
if (isEmpty(item)) {
continue;
}
clonedItems[i] = item.clone();
}
return clonedItems;
}
private static InventoryData parseInventoryData(final Inventory inventory, final ItemStack[] items, final int maxStack, final boolean includeArmor) {
final ItemStack[] inventoryContents = inventory.getContents();
final List<Integer> emptySlots = new ArrayList<>();
final HashMap<ItemStack, List<Integer>> partialSlots = new HashMap<>();
for (int i = 0; i < inventoryContents.length; i++) {
if (!includeArmor && isArmorSlot(i)) {
continue;
}
final ItemStack invItem = inventoryContents[i];
if (isEmpty(invItem)) {
emptySlots.add(i);
} else {
for (final ItemStack newItem : items) {
if (invItem.getAmount() < Math.max(maxStack, invItem.getMaxStackSize()) && invItem.isSimilar(newItem)) {
partialSlots.computeIfAbsent(newItem, k -> new ArrayList<>()).add(i);
}
}
}
}
// Convert empty armor slots to partial slots if we have armor items in the inventory, otherwise remove them from the empty slots.
if (includeArmor) {
ItemStack helm = null;
ItemStack chest = null;
ItemStack legs = null;
ItemStack boots = null;
for (final ItemStack item : items) {
if (isEmpty(item)) {
continue;
}
if (helm == null && MaterialUtil.isHelmet(item.getType())) {
helm = item;
if (emptySlots.contains(HELM_SLOT)) {
partialSlots.computeIfAbsent(helm, k -> new ArrayList<>()).add(HELM_SLOT);
}
} else if (chest == null && MaterialUtil.isChestplate(item.getType())) {
chest = item;
if (emptySlots.contains(CHEST_SLOT)) {
partialSlots.computeIfAbsent(chest, k -> new ArrayList<>()).add(CHEST_SLOT);
}
} else if (legs == null && MaterialUtil.isLeggings(item.getType())) {
legs = item;
if (emptySlots.contains(LEG_SLOT)) {
partialSlots.computeIfAbsent(legs, k -> new ArrayList<>()).add(LEG_SLOT);
}
} else if (boots == null && MaterialUtil.isBoots(item.getType())) {
boots = item;
if (emptySlots.contains(BOOT_SLOT)) {
partialSlots.computeIfAbsent(boots, k -> new ArrayList<>()).add(BOOT_SLOT);
}
}
}
emptySlots.remove((Object) HELM_SLOT);
emptySlots.remove((Object) CHEST_SLOT);
emptySlots.remove((Object) LEG_SLOT);
emptySlots.remove((Object) BOOT_SLOT);
}
return new InventoryData(emptySlots, partialSlots);
}
private static boolean isEmpty(final ItemStack stack) {
return stack == null || MaterialUtil.isAir(stack.getType());
}
private static boolean isArmorSlot(final int slot) {
return slot == HELM_SLOT || slot == CHEST_SLOT || slot == LEG_SLOT || slot == BOOT_SLOT;
}
}

View File

@ -0,0 +1,24 @@
package com.earth2me.essentials.craftbukkit;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.List;
public class InventoryData {
private final List<Integer> emptySlots;
private final HashMap<ItemStack, List<Integer>> partialSlots;
public InventoryData(List<Integer> emptySlots, HashMap<ItemStack, List<Integer>> partialSlots) {
this.emptySlots = emptySlots;
this.partialSlots = partialSlots;
}
public List<Integer> getEmptySlots() {
return emptySlots;
}
public HashMap<ItemStack, List<Integer>> getPartialSlots() {
return partialSlots;
}
}

View File

@ -1,245 +0,0 @@
package com.earth2me.essentials.craftbukkit;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/*
* This class can be removed when https://github.com/Bukkit/CraftBukkit/pull/193 is accepted to CraftBukkit
*/
public final class InventoryWorkaround {
/*
Spigot 1.9, for whatever reason, decided to merge the armor and main player inventories without providing a way
to access the main inventory. There's lots of ugly code in here to work around that.
*/
private static final int USABLE_PLAYER_INV_SIZE = 36;
private static final boolean IS_OFFHAND = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01);
private InventoryWorkaround() {
}
private static int firstPartial(final Inventory inventory, final ItemStack item, final int maxAmount) {
if (item == null) {
return -1;
}
final ItemStack[] stacks = inventory.getContents();
for (int i = 0; i < stacks.length; i++) {
final ItemStack cItem = stacks[i];
if (cItem != null && cItem.getAmount() < maxAmount && cItem.isSimilar(item)) {
return i;
}
}
return -1;
}
private static boolean isCombinedInventory(final Inventory inventory) {
return inventory instanceof PlayerInventory && inventory.getContents().length > USABLE_PLAYER_INV_SIZE;
}
// Clears inventory without clearing armor
public static void clearInventoryNoArmor(final PlayerInventory inventory) {
if (isCombinedInventory(inventory)) {
for (int i = 0; i < USABLE_PLAYER_INV_SIZE; i++) {
inventory.setItem(i, null);
}
} else {
inventory.clear();
}
}
private static Inventory makeTruncatedPlayerInventory(final PlayerInventory playerInventory) {
final Inventory fakeInventory = Bukkit.getServer().createInventory(null, USABLE_PLAYER_INV_SIZE);
fakeInventory.setContents(Arrays.copyOf(playerInventory.getContents(), fakeInventory.getSize()));
return fakeInventory;
}
// Returns what it couldn't store
// This will will abort if it couldn't store all items
public static Map<Integer, ItemStack> addAllItems(final Inventory inventory, final ItemStack... items) {
final ItemStack[] contents = inventory.getContents();
final Inventory fakeInventory;
if (isCombinedInventory(inventory)) {
fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
} else {
fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType());
fakeInventory.setContents(contents);
}
final Map<Integer, ItemStack> overflow = addItems(fakeInventory, items);
if (overflow.isEmpty()) {
addItems(inventory, items);
return null;
}
return addItems(fakeInventory, items);
}
public static Map<Integer, ItemStack> addAllOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) {
final ItemStack[] contents = inventory.getContents();
final Inventory fakeInventory;
if (isCombinedInventory(inventory)) {
fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
} else {
fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType());
fakeInventory.setContents(contents);
}
final Map<Integer, ItemStack> overflow = addOversizedItems(fakeInventory, oversizedStacks, items);
if (overflow.isEmpty()) {
addOversizedItems(inventory, oversizedStacks, items);
return null;
}
return overflow;
}
// Returns what it couldn't store
public static Map<Integer, ItemStack> addItems(final Inventory inventory, final ItemStack... items) {
return addOversizedItems(inventory, 0, items);
}
// Returns what it couldn't store
// Set oversizedStack to below normal stack size to disable oversized stacks
public static Map<Integer, ItemStack> addOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) {
if (isCombinedInventory(inventory)) {
final Inventory fakeInventory = makeTruncatedPlayerInventory((PlayerInventory) inventory);
final Map<Integer, ItemStack> overflow = addOversizedItems(fakeInventory, oversizedStacks, items);
for (int i = 0; i < fakeInventory.getContents().length; i++) {
inventory.setItem(i, fakeInventory.getContents()[i]);
}
return overflow;
}
final Map<Integer, ItemStack> leftover = new HashMap<>();
/*
* TODO: some optimization - Create a 'firstPartial' with a 'fromIndex' - Record the lastPartial per Material -
* Cache firstEmpty result
*/
// combine items
final ItemStack[] combined = new ItemStack[items.length];
for (final ItemStack item : items) {
if (item == null || item.getAmount() < 1) {
continue;
}
for (int j = 0; j < combined.length; j++) {
if (combined[j] == null) {
combined[j] = item.clone();
break;
}
if (combined[j].isSimilar(item)) {
combined[j].setAmount(combined[j].getAmount() + item.getAmount());
break;
}
}
}
for (int i = 0; i < combined.length; i++) {
final ItemStack item = combined[i];
if (item == null || item.getType() == Material.AIR) {
continue;
}
while (true) {
// Do we already have a stack of it?
final int maxAmount = Math.max(oversizedStacks, item.getType().getMaxStackSize());
final int firstPartial = firstPartial(inventory, item, maxAmount);
// Drat! no partial stack
if (firstPartial == -1) {
// Find a free spot!
final int firstFree = inventory.firstEmpty();
if (firstFree == -1) {
// No space at all!
leftover.put(i, item);
break;
} else {
// More than a single stack!
if (item.getAmount() > maxAmount) {
final ItemStack stack = item.clone();
stack.setAmount(maxAmount);
inventory.setItem(firstFree, stack);
item.setAmount(item.getAmount() - maxAmount);
} else {
// Just store it
inventory.setItem(firstFree, item);
break;
}
}
} else {
// So, apparently it might only partially fit, well lets do just that
final ItemStack partialItem = inventory.getItem(firstPartial);
final int amount = item.getAmount();
final int partialAmount = partialItem.getAmount();
// Check if it fully fits
if (amount + partialAmount <= maxAmount) {
partialItem.setAmount(amount + partialAmount);
break;
}
// It fits partially
partialItem.setAmount(maxAmount);
item.setAmount(amount + partialAmount - maxAmount);
}
}
}
return leftover;
}
@SuppressWarnings("deprecation")
public static void setItemInMainHand(final Player p, final ItemStack item) {
if (IS_OFFHAND) {
p.getInventory().setItemInMainHand(item);
} else {
p.setItemInHand(item);
}
}
@SuppressWarnings("deprecation")
public static void setItemInMainHand(final EntityEquipment invent, final ItemStack item) {
if (IS_OFFHAND) {
invent.setItemInMainHand(item);
} else {
invent.setItemInHand(item);
}
}
@SuppressWarnings("deprecation")
public static void setItemInMainHandDropChance(final EntityEquipment invent, final float chance) {
if (IS_OFFHAND) {
invent.setItemInMainHandDropChance(chance);
} else {
invent.setItemInHandDropChance(chance);
}
}
public static void setItemInOffHand(final Player p, final ItemStack item) {
if (IS_OFFHAND) {
p.getInventory().setItemInOffHand(item);
}
}
public static int clearItemInOffHand(final Player p, final ItemStack item) {
if (IS_OFFHAND) {
int removedAmount = 0;
if (p.getInventory().getItemInOffHand().getType().equals(item.getType())) {
removedAmount = p.getInventory().getItemInOffHand().getAmount();
p.getInventory().setItemInOffHand(null);
}
return removedAmount;
}
return 0;
}
}

View File

@ -2,6 +2,7 @@ package com.earth2me.essentials.items;
import com.earth2me.essentials.IConf;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.FormatUtil;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.VersionUtil;
@ -156,14 +157,14 @@ public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb {
} else if (args[0].equalsIgnoreCase("hand")) {
is.add(user.getItemInHand().clone());
} else if (args[0].equalsIgnoreCase("inventory") || args[0].equalsIgnoreCase("invent") || args[0].equalsIgnoreCase("all")) {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), true)) {
if (stack == null || stack.getType() == Material.AIR) {
continue;
}
is.add(stack.clone());
}
} else if (args[0].equalsIgnoreCase("blocks")) {
for (final ItemStack stack : user.getBase().getInventory().getContents()) {
for (final ItemStack stack : Inventories.getInventory(user.getBase(), true)) {
if (stack == null || stack.getType() == Material.AIR || !stack.getType().isBlock()) {
continue;
}

View File

@ -4,6 +4,7 @@ import com.earth2me.essentials.ChargeException;
import com.earth2me.essentials.Enchantments;
import com.earth2me.essentials.Trade;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import net.ess3.api.IEssentials;
import net.ess3.provider.MaterialTagProvider;
import org.bukkit.enchantments.Enchantment;
@ -66,7 +67,7 @@ public class SignEnchant extends EssentialsSign {
@Override
protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException {
final ItemStack playerHand = player.getBase().getItemInHand();
final ItemStack playerHand = Inventories.getItemInHand(player.getBase());
final MaterialTagProvider tagProvider = ess.getMaterialTagProvider();
final String itemName = sign.getLine(1);
final ItemStack search = itemName.equals("*") || itemName.equalsIgnoreCase("any") || (tagProvider != null && tagProvider.tagExists(itemName) && tagProvider.isTagged(itemName, playerHand.getType())) ? null : getItemStack(itemName, 1, ess);

View File

@ -5,6 +5,7 @@ import com.earth2me.essentials.Trade;
import com.earth2me.essentials.Trade.OverflowType;
import com.earth2me.essentials.Trade.TradeType;
import com.earth2me.essentials.User;
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.NumberUtil;
import net.ess3.api.IEssentials;
@ -84,10 +85,11 @@ public class SignTrade extends EssentialsSign {
private Trade rechargeSign(final ISign sign, final IEssentials ess, final User player) throws SignException, ChargeException {
final Trade trade = getTrade(sign, 2, AmountType.COST, false, true, ess);
if (trade.getItemStack() != null && player.getBase().getItemInHand() != null && trade.getItemStack().getType() == player.getBase().getItemInHand().getType() && MaterialUtil.getDamage(trade.getItemStack()) == MaterialUtil.getDamage(player.getBase().getItemInHand()) && trade.getItemStack().getEnchantments().equals(player.getBase().getItemInHand().getEnchantments())) {
ItemStack stack = Inventories.getItemInHand(player.getBase());
if (trade.getItemStack() != null && stack != null && !MaterialUtil.isAir(stack.getType()) && trade.getItemStack().getType() == stack.getType() && MaterialUtil.getDamage(trade.getItemStack()) == MaterialUtil.getDamage(stack) && trade.getItemStack().getEnchantments().equals(stack.getEnchantments())) {
final int amount = trade.getItemStack().getAmount();
if (player.getBase().getInventory().containsAtLeast(trade.getItemStack(), amount)) {
final ItemStack stack = player.getBase().getItemInHand().clone();
if (Inventories.containsAtLeast(player.getBase(), trade.getItemStack(), amount)) {
stack = stack.clone();
stack.setAmount(amount);
final Trade store = new Trade(stack, ess);
addAmount(sign, 2, store, ess);