From 5f6cca83ceb002b8a6886d2a893e2c6ad8d463ef Mon Sep 17 00:00:00 2001 From: KHobbits Date: Mon, 6 May 2013 06:40:22 +0100 Subject: [Feature] Withdraw from trade signs without dropping items as overflow. [EXPERIMENTAL] --- Essentials/src/com/earth2me/essentials/Kit.java | 3 +- Essentials/src/com/earth2me/essentials/Trade.java | 85 +++++++++++---- .../essentials/commands/Commandessentials.java | 1 + .../craftbukkit/InventoryWorkaround.java | 14 ++- .../src/com/earth2me/essentials/signs/SignBuy.java | 2 +- .../earth2me/essentials/signs/SignProtection.java | 6 +- .../com/earth2me/essentials/signs/SignSell.java | 3 +- .../com/earth2me/essentials/signs/SignTrade.java | 118 ++++++++++++++++----- 8 files changed, 172 insertions(+), 60 deletions(-) diff --git a/Essentials/src/com/earth2me/essentials/Kit.java b/Essentials/src/com/earth2me/essentials/Kit.java index 16cb35fc9..2807a06ad 100644 --- a/Essentials/src/com/earth2me/essentials/Kit.java +++ b/Essentials/src/com/earth2me/essentials/Kit.java @@ -2,6 +2,7 @@ package com.earth2me.essentials; import static com.earth2me.essentials.I18n._; import static com.earth2me.essentials.I18n.capitalCase; +import com.earth2me.essentials.Trade.OverflowType; import com.earth2me.essentials.commands.NoChargeException; import com.earth2me.essentials.craftbukkit.InventoryWorkaround; import com.earth2me.essentials.textreader.IText; @@ -137,7 +138,7 @@ public class Kit { BigDecimal value = new BigDecimal(kitItem.substring(ess.getSettings().getCurrencySymbol().length()).trim()); Trade t = new Trade(value, ess); - t.pay(user); + t.pay(user, OverflowType.DROP); continue; } diff --git a/Essentials/src/com/earth2me/essentials/Trade.java b/Essentials/src/com/earth2me/essentials/Trade.java index a770bfc29..8830df9a1 100644 --- a/Essentials/src/com/earth2me/essentials/Trade.java +++ b/Essentials/src/com/earth2me/essentials/Trade.java @@ -35,6 +35,14 @@ public class Trade ITEM } + + public enum OverflowType + { + ABORT, + DROP, + RETURN + } + public Trade(final String command, final IEssentials ess) { this(command, null, null, null, null, ess); @@ -112,14 +120,13 @@ public class Trade } } - public void pay(final IUser user) + public boolean pay(final IUser user) { - pay(user, true); + return pay(user, OverflowType.ABORT) == null; } - public boolean pay(final IUser user, final boolean dropItems) + public Map pay(final IUser user, final OverflowType type) { - boolean success = true; if (getMoney() != null && getMoney().signum() > 0) { if (ess.getSettings().isDebug()) @@ -130,33 +137,65 @@ public class Trade } if (getItemStack() != null) { - if (dropItems) + // This stores the would be overflow + Map overFlow = InventoryWorkaround.addAllItems(user.getInventory(), getItemStack()); + + if (overFlow != null) { - final Map leftOver = InventoryWorkaround.addItems(user.getInventory(), getItemStack()); - final Location loc = user.getLocation(); - for (ItemStack itemStack : leftOver.values()) + switch (type) { - final int maxStackSize = itemStack.getType().getMaxStackSize(); - final int stacks = itemStack.getAmount() / maxStackSize; - final int leftover = itemStack.getAmount() % maxStackSize; - final Item[] itemStacks = new Item[stacks + (leftover > 0 ? 1 : 0)]; - for (int i = 0; i < stacks; i++) + case ABORT: + if (ess.getSettings().isDebug()) + { + ess.getLogger().log(Level.INFO, "abort paying " + user.getName() + " itemstack " + getItemStack().toString() + " due to lack of inventory space "); + } + + return overFlow; + + case RETURN: + // Pay the user the items, and return overflow + final Map returnStack = InventoryWorkaround.addItems(user.getInventory(), getItemStack()); + user.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 leftOver = InventoryWorkaround.addItems(user.getInventory(), getItemStack()); + final Location loc = user.getLocation(); + for (ItemStack loStack : leftOver.values()) { - final ItemStack stack = itemStack.clone(); - stack.setAmount(maxStackSize); - itemStacks[i] = loc.getWorld().dropItem(loc, stack); + 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 (leftover > 0) + if (ess.getSettings().isDebug()) { - final ItemStack stack = itemStack.clone(); - stack.setAmount(leftover); - itemStacks[stacks] = loc.getWorld().dropItem(loc, stack); + ess.getLogger().log(Level.INFO, "paying " + user.getName() + " partial itemstack " + getItemStack().toString() + " and dropping overflow " + leftOver.get(0).toString()); } } } - else + else if (ess.getSettings().isDebug()) { - success = InventoryWorkaround.addAllItems(user.getInventory(), getItemStack()); + ess.getLogger().log(Level.INFO, "paying " + user.getName() + " itemstack " + getItemStack().toString()); } user.updateInventory(); } @@ -164,7 +203,7 @@ public class Trade { SetExpFix.setTotalExperience(user, SetExpFix.getTotalExperience(user) + getExperience()); } - return success; + return null; } public void charge(final IUser user) throws ChargeException diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java b/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java index 1fd0720ee..671a5a2b0 100644 --- a/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandessentials.java @@ -222,6 +222,7 @@ public class Commandessentials extends EssentialsCommand { sender.sendMessage("This sub-command will delete users who havent logged in in the last days."); sender.sendMessage("Optional parameters define the minium amount required to prevent deletion."); + sender.sendMessage("Unless you define larger default values, this command wil ignore people who have more than 0 money/homes/bans."); throw new Exception("/ cleanup [money] [homes] [ban count]"); } sender.sendMessage(_("cleaning")); diff --git a/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java b/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java index 2e05f5c43..d5da047fe 100644 --- a/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java +++ b/Essentials/src/com/earth2me/essentials/craftbukkit/InventoryWorkaround.java @@ -34,23 +34,29 @@ public final class InventoryWorkaround return -1; } - public static boolean addAllItems(final Inventory inventory, final ItemStack... items) + // Returns what it couldnt store + // This will will abort if it couldn't store all items + public static Map addAllItems(final Inventory inventory, final ItemStack... items) { final Inventory fakeInventory = Bukkit.getServer().createInventory(null, inventory.getType()); fakeInventory.setContents(inventory.getContents()); - if (addItems(fakeInventory, items).isEmpty()) + Map overFlow = addItems(fakeInventory, items); + if (overFlow.isEmpty()) { addItems(inventory, items); - return true; + return null; } - return false; + return addItems(fakeInventory, items); } + // Returns what it couldnt store public static Map addItems(final Inventory inventory, final ItemStack... items) { return addOversizedItems(inventory, 0, items); } + // Returns what it couldnt store + // Set oversizedStack to below normal stack size to disable oversized stacks public static Map addOversizedItems(final Inventory inventory, final int oversizedStacks, final ItemStack... items) { final Map leftover = new HashMap(); diff --git a/Essentials/src/com/earth2me/essentials/signs/SignBuy.java b/Essentials/src/com/earth2me/essentials/signs/SignBuy.java index d675a598c..7f4b824ca 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignBuy.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignBuy.java @@ -27,7 +27,7 @@ public class SignBuy extends EssentialsSign final Trade items = getTrade(sign, 1, 2, player, ess); final Trade charge = getTrade(sign, 3, ess); charge.isAffordableFor(player); - if (!items.pay(player, false)) + if (!items.pay(player)) { throw new ChargeException("Inventory full"); //TODO: TL } diff --git a/Essentials/src/com/earth2me/essentials/signs/SignProtection.java b/Essentials/src/com/earth2me/essentials/signs/SignProtection.java index b5a679324..c336ec8c8 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignProtection.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignProtection.java @@ -2,6 +2,7 @@ package com.earth2me.essentials.signs; import static com.earth2me.essentials.I18n._; import com.earth2me.essentials.*; +import com.earth2me.essentials.Trade.OverflowType; import java.util.*; import org.bukkit.Location; import org.bukkit.Material; @@ -10,6 +11,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.inventory.ItemStack; + @Deprecated // This sign will be removed soon public class SignProtection extends EssentialsSign { @@ -81,7 +83,7 @@ public class SignProtection extends EssentialsSign { block.setType(Material.AIR); final Trade trade = new Trade(new ItemStack(Material.SIGN, 1), ess); - trade.pay(player); + trade.pay(player, OverflowType.DROP); } } } @@ -241,7 +243,7 @@ public class SignProtection extends EssentialsSign { return protectedBlocks; } - + @Override public boolean areHeavyEventRequired() { diff --git a/Essentials/src/com/earth2me/essentials/signs/SignSell.java b/Essentials/src/com/earth2me/essentials/signs/SignSell.java index 442a503c2..ea2022f7f 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignSell.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignSell.java @@ -3,6 +3,7 @@ package com.earth2me.essentials.signs; import com.earth2me.essentials.ChargeException; import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.Trade; +import com.earth2me.essentials.Trade.OverflowType; import com.earth2me.essentials.User; @@ -27,7 +28,7 @@ public class SignSell extends EssentialsSign final Trade charge = getTrade(sign, 1, 2, player, ess); final Trade money = getTrade(sign, 3, ess); charge.isAffordableFor(player); - money.pay(player); + money.pay(player, OverflowType.DROP); charge.charge(player); Trade.log("Sign", "Sell", "Interact", username, charge, username, money, sign.getBlock().getLocation(), ess); return true; diff --git a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java index eb6cc60ee..eb611e7ea 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java @@ -3,7 +3,9 @@ package com.earth2me.essentials.signs; import static com.earth2me.essentials.I18n._; import com.earth2me.essentials.Trade.TradeType; import com.earth2me.essentials.*; +import com.earth2me.essentials.Trade.OverflowType; import java.math.BigDecimal; +import java.util.Map; import org.bukkit.inventory.ItemStack; //TODO: TL exceptions @@ -14,13 +16,21 @@ public class SignTrade extends EssentialsSign super("Trade"); } + + public enum AmountType + { + TOTAL, + ROUNDED, + COST + } + @Override protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException { validateTrade(sign, 1, false, ess); validateTrade(sign, 2, true, ess); - final Trade trade = getTrade(sign, 2, true, true, ess); - final Trade charge = getTrade(sign, 1, true, false, ess); + final Trade trade = getTrade(sign, 2, AmountType.ROUNDED, true, ess); + final Trade charge = getTrade(sign, 1, AmountType.ROUNDED, false, ess); if (trade.getType() == charge.getType() && (trade.getType() != TradeType.ITEM || trade.getItemStack().getType().equals(charge.getItemStack().getType()))) { throw new SignException("You cannot trade for the same item type."); @@ -41,9 +51,20 @@ public class SignTrade extends EssentialsSign Trade stored = null; try { - stored = getTrade(sign, 1, true, true, ess); + stored = getTrade(sign, 1, AmountType.TOTAL, true, ess); subtractAmount(sign, 1, stored, ess); - stored.pay(player); + + Map withdraw = stored.pay(player, OverflowType.RETURN); + + if (withdraw == null) + { + Trade.log("Sign", "Trade", "Withdraw", username, store, username, null, sign.getBlock().getLocation(), ess); + } + else + { + setAmount(sign, 1, BigDecimal.valueOf(withdraw.get(0).getAmount()), ess); + Trade.log("Sign", "Trade", "Withdraw", username, stored, username, new Trade(withdraw.get(0), ess), sign.getBlock().getLocation(), ess); + } } catch (SignException e) { @@ -52,16 +73,16 @@ public class SignTrade extends EssentialsSign throw new SignException(_("tradeSignEmptyOwner"), e); } } - Trade.log("Sign", "Trade", "OwnerInteract", username, store, username, stored, sign.getBlock().getLocation(), ess); + Trade.log("Sign", "Trade", "Deposit", username, store, username, null, sign.getBlock().getLocation(), ess); } else { - final Trade charge = getTrade(sign, 1, false, false, ess); - final Trade trade = getTrade(sign, 2, false, true, ess); + final Trade charge = getTrade(sign, 1, AmountType.COST, false, ess); + final Trade trade = getTrade(sign, 2, AmountType.COST, true, ess); charge.isAffordableFor(player); addAmount(sign, 1, charge, ess); subtractAmount(sign, 2, trade, ess); - if (!trade.pay(player, false)) + if (!trade.pay(player)) { subtractAmount(sign, 1, charge, ess); addAmount(sign, 2, trade, ess); @@ -76,7 +97,7 @@ 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, false, false, ess); + final Trade trade = getTrade(sign, 2, AmountType.COST, false, ess); if (trade.getItemStack() != null && player.getItemInHand() != null && trade.getItemStack().getTypeId() == player.getItemInHand().getTypeId() && trade.getItemStack().getDurability() == player.getItemInHand().getDurability() @@ -105,11 +126,24 @@ public class SignTrade extends EssentialsSign { try { - final Trade stored1 = getTrade(sign, 1, true, false, ess); - final Trade stored2 = getTrade(sign, 2, true, false, ess); - stored1.pay(player); - stored2.pay(player); - Trade.log("Sign", "Trade", "Break", username, stored2, username, stored1, sign.getBlock().getLocation(), ess); + final Trade stored1 = getTrade(sign, 1, AmountType.TOTAL, false, ess); + final Trade stored2 = getTrade(sign, 2, AmountType.TOTAL, false, ess); + Map withdraw1 = stored1.pay(player, OverflowType.RETURN); + Map withdraw2 = stored2.pay(player, OverflowType.RETURN); + + if (withdraw1 == null && withdraw2 == null) + { + Trade.log("Sign", "Trade", "Break", username, stored2, username, stored1, sign.getBlock().getLocation(), ess); + return true; + } + + setAmount(sign, 1, BigDecimal.valueOf(withdraw1 == null ? 0L : withdraw1.get(0).getAmount()), ess); + Trade.log("Sign", "Trade", "Withdraw", username, stored1, username, withdraw1 == null ? null : new Trade(withdraw1.get(0), ess), sign.getBlock().getLocation(), ess); + + setAmount(sign, 2, BigDecimal.valueOf(withdraw2 == null ? 0L : withdraw2.get(0).getAmount()), ess); + Trade.log("Sign", "Trade", "Withdraw", username, stored2, username, withdraw2 == null ? null : new Trade(withdraw2.get(0), ess), sign.getBlock().getLocation(), ess); + + sign.updateSign(); } catch (SignException e) { @@ -119,7 +153,7 @@ public class SignTrade extends EssentialsSign } throw e; } - return true; + return false; } else { @@ -208,7 +242,7 @@ public class SignTrade extends EssentialsSign throw new SignException(_("invalidSignLine", index + 1)); } - protected final Trade getTrade(final ISign sign, final int index, final boolean fullAmount, final boolean notEmpty, final IEssentials ess) throws SignException + protected final Trade getTrade(final ISign sign, final int index, final AmountType amountType, final boolean notEmpty, final IEssentials ess) throws SignException { final String line = sign.getLine(index).trim(); if (line.isEmpty()) @@ -225,7 +259,7 @@ public class SignTrade extends EssentialsSign final BigDecimal amount = notEmpty ? getBigDecimalPositive(split[1]) : getBigDecimal(split[1]); if (money != null && amount != null) { - return new Trade(fullAmount ? amount : money, ess); + return new Trade(amountType == AmountType.COST ? money : amount, ess); } } catch (SignException e) @@ -240,24 +274,30 @@ public class SignTrade extends EssentialsSign { final int stackamount = getIntegerPositive(split[0]); int amount = getInteger(split[2]); - amount -= amount % stackamount; + if (amountType == AmountType.ROUNDED) + { + amount -= amount % stackamount; + } if (notEmpty && (amount < 1 || stackamount < 1)) { throw new SignException(_("tradeSignEmpty")); } - return new Trade(fullAmount ? amount : stackamount, ess); + return new Trade((amountType == AmountType.COST ? stackamount : amount), ess); } else { final int stackamount = getIntegerPositive(split[0]); final ItemStack item = getItemStack(split[1], stackamount, ess); int amount = getInteger(split[2]); - amount -= amount % stackamount; + if (amountType == AmountType.ROUNDED) + { + amount -= amount % stackamount; + } if (notEmpty && (amount < 1 || stackamount < 1 || item.getTypeId() == 0)) { throw new SignException(_("tradeSignEmpty")); } - item.setAmount(fullAmount ? amount : stackamount); + item.setAmount(amountType == AmountType.COST ? stackamount : amount); return new Trade(item, ess); } } @@ -304,6 +344,31 @@ public class SignTrade extends EssentialsSign //TODO: Translate these exceptions. private void changeAmount(final ISign sign, final int index, final BigDecimal value, final IEssentials ess) throws SignException + { + final String line = sign.getLine(index).trim(); + if (line.isEmpty()) + { + throw new SignException("Empty line"); + } + final String[] split = line.split("[ :]+"); + + if (split.length == 2) + { + final BigDecimal amount = getBigDecimal(split[1]).add(value); + setAmount(sign, index, amount, ess); + return; + } + if (split.length == 3) + { + final BigDecimal amount = getBigDecimal(split[2]).add(value); + setAmount(sign, index, amount, ess); + return; + } + throw new SignException(_("invalidSignLine", index + 1)); + } + + //TODO: Translate these exceptions. + private void setAmount(final ISign sign, final int index, final BigDecimal value, final IEssentials ess) throws SignException { final String line = sign.getLine(index).trim(); @@ -319,7 +384,7 @@ public class SignTrade extends EssentialsSign final BigDecimal amount = getBigDecimal(split[1]); if (money != null && amount != null) { - final String newline = Util.shortCurrency(money, ess) + ":" + Util.shortCurrency(amount.add(value), ess).substring(1); + final String newline = Util.shortCurrency(money, ess) + ":" + Util.shortCurrency(value, ess).substring(1); if (newline.length() > 15) { throw new SignException("This sign is full: Line too long!"); @@ -334,8 +399,7 @@ public class SignTrade extends EssentialsSign if (split[1].equalsIgnoreCase("exp") || split[1].equalsIgnoreCase("xp")) { final int stackamount = getIntegerPositive(split[0]); - final int amount = getInteger(split[2]); - final String newline = stackamount + " " + split[1] + ":" + (amount + value.intValueExact()); + final String newline = stackamount + " " + split[1] + ":" + (value.intValueExact()); if (newline.length() > 15) { throw new SignException("This sign is full: Line too long!"); @@ -346,10 +410,8 @@ public class SignTrade extends EssentialsSign else { final int stackamount = getIntegerPositive(split[0]); - //TODO: Unused local variable - final ItemStack item = getItemStack(split[1], stackamount, ess); - final int amount = getInteger(split[2]); - final String newline = stackamount + " " + split[1] + ":" + (amount + value.intValueExact()); + getItemStack(split[1], stackamount, ess); + final String newline = stackamount + " " + split[1] + ":" + (value.intValueExact()); if (newline.length() > 15) { throw new SignException("This sign is full: Line too long!"); -- cgit v1.2.3